import argparse
import rdflib

import trygvis.eda.digikey.rdf as digikey_rdf
from trygvis.eda import cli, EdaException


class MakeBomCommand(cli.CliCommand):
    def __init__(self):
        super().__init__("make-bom", "Create a BOM for a project with all info for each part.")

    def run(self, argv):
        p = argparse.ArgumentParser(prog=self.key, description=self.description)
        p.add_argument("--project")
        p.add_argument("--version")
        args = p.parse_args(argv)

        run(args)


class DigiKeyPart(object):
    def __init__(self, part_number):
        self.part_number = part_number
        self.attributes = {}

    def set_attribute(self, key, value):
        self.attributes[key] = value


class Component(object):
    def __init__(self, ref, value):
        self.ref = ref
        self.value = value
        self.fields = {}

    def set_field(self, field_name, field_value):
        self.fields[field_name] = field_value


def run(args):
    cli.with_database(lambda g: work(args, g))


def work(args, g):
    config = cli.read_config()
    project_url = args.project if args.project is not None else config['project']['url']

    components = {}
    dk_parts = {}

    if args.version is not None:
        version_url = args.version
        version_uuid = None
        timestamp = None
    else:
        cli.info("Finding latest version")
        res = cli.sparql(g, """
SELECT
?project ?timestamp ?version_uuid
WHERE {
    ?project a kicad:project ;
        kicad:timestamp ?timestamp ;
        kicad:version-uuid ?version_uuid ;
        kicad:version-of ?orig_project
  .
}
ORDER BY DESC(?timestamp)
LIMIT 1
""", init_bindings={"orig_project": rdflib.URIRef(project_url)})

        for row in res:
            version_url = row.project
            version_uuid = row.version_uuid
            timestamp = row.timestamp
            break
        else:
            raise EdaException("Could not find any version of project %s" % project_url)

    cli.info("Loading components for version %s, uuid=%s, timestamp=%s" % (version_url, version_uuid, timestamp))

    res = cli.sparql(g, """
SELECT
    ?ref ?value
WHERE {
    ?version a kicad:project ;
        kicad:component ?cmp .
    ?cmp a kicad:component ;
        kicad:value ?value ;
        rdfs:label ?ref .
}
ORDER BY ?ref
""", init_bindings={"version": rdflib.URIRef(version_url)})

    for row in res:
        c = Component(row.ref, row.value)
        components[row.ref] = c
        cli.info('ref=%s, value=%s' % (c.ref, c.value))

    if len(components) == 0:
        raise EdaException("Could not find any components")

    cli.info("Loading custom component attributes")
    res = cli.sparql(g, """
SELECT
    ?ref ?field ?field_name ?field_value
WHERE {
    ?version a kicad:project ;
        kicad:component ?cmp .

    ?cmp a kicad:component ;
        rdfs:label ?ref ;
        kicad:field ?field .

    ?field a kicad:field ;
        kicad:field-name ?field_name ;
        kicad:field-value ?field_value .
}
ORDER BY ?ref ?field_name
""", init_bindings={"version": rdflib.URIRef(version_url)})

    for row in res:
        # cli.debug('row: %s' % str(row))
        c = components[row.ref]
        assert isinstance(c, Component)
        c.set_field(row.field_name, row.field_value)
        cli.info('%5s: %-20s %s' % (c.ref, row.field_name + ':', row.field_value))

    cli.info("Loading Digi-Key parts for project")
    res = cli.sparql(g, """
SELECT
?ref ?part_number ?type ?value ?attr_type
WHERE {
    ?version a kicad:project ;
        kicad:component ?cmp .

    ?cmp a kicad:component ;
        rdfs:label ?ref ;
        kicad:field ?d .

    ?d kicad:field-name "digikey" ;
        kicad:field-value ?part_number .

    ?part a dk:part ;
    #     rdfs:label ?label ;
        dk:partNumber ?part_number ;
        dk:attribute-value ?attr_value .

 ?attr_value rdfs:label ?value .
 ?attr_type a dk:attributeType ;
           rdfs:label ?type ;
           dk:value ?attr_value .
}
ORDER BY ?ref ?attr_type ?attr_value
""", init_bindings={"version": rdflib.URIRef(version_url)})

    for row in res:
        pn = row.part_number

        if not hasattr(dk_parts, pn):
            part = DigiKeyPart(pn)
            dk_parts[pn] = part
        else:
            part = dk_parts[pn]

        part.set_attribute(row.type, row.value)
        cli.info('%-30s %-50s %-50s %s' % (pn, row.type, row.value, row.attr_type))

    cli.info("Footprint check:")
    res = cli.sparql(g, """
SELECT
?ref ?footprint ?part_number ?package_value ?case_value
# *
WHERE {
    ?version a kicad:project ;
        kicad:component ?cmp .

    ?cmp a kicad:component ;
        rdfs:label ?ref ;
        kicad:field ?dk_field .

    optional {
        ?cmp kicad:footprint ?footprint_url  .
        ?footprint_url rdfs:label ?footprint .
    } .

    ?dk_field kicad:field-name "digikey" ;
        kicad:field-value ?part_number .
    ?part a dk:part ;
        dk:partNumber ?part_number .

    optional {
        ?part dk:attribute-value ?package_url .
        ?package_url rdfs:label ?package_value .
        ?package_type a dk:attributeType ; dk:value ?package_url .
    } .

#  optional {
#    ?part dk:attribute-value ?case_url .
#    ?case_url rdfs:label ?case_value .
#    ?case_type a dk:attributeType ; dk:value ?case_url .
#  } .

#  VALUES (?project_url) { (...) } .
#  VALUES (?package_type) { (dk-attr-type:pv16) } .
#  VALUES (?case_type) { (dk-attr-type:pv1291) } .
}
ORDER BY ?ref
""", init_bindings={"version": rdflib.URIRef(version_url),
                    "package_type": digikey_rdf.DIGIKEY_ATTRIBUTE_TYPE["pv16"],
                    "cast_type": digikey_rdf.DIGIKEY_ATTRIBUTE_TYPE["pv1291"]})

    for row in res:
        cli.info("%-5s %-50s %-50s %s %s" % (row.ref, row.part_number, row.footprint, row.package_value, row.case_value))