#
#   Copyright (c) 2021-2022, 2025 eGauge Systems LLC
# 	4805 Sterling Dr, Suite 1
# 	Boulder, CO 80301
# 	voice: 720-545-9767
# 	email: davidm@egauge.net
#
#   All rights reserved.
#
#   This code is the property of eGauge Systems LLC and may not be
#   copied, modified, or disclosed without any prior and written
#   permission from eGauge Systems LLC.
#
"""KiCad EPIC scripts."""

import argparse
import logging
import sys
import traceback
from argparse import RawDescriptionHelpFormatter as RawDescHelpFormatter
from pathlib import Path

from epic.base import format_part_number

from . import schematics
from .bom import BOM
from .csv import CSVBOM
from .epic_client import EPICAPIClient
from .error import Error, UnknownFlavorsError
from .vendors_cache import VendorsCache


def epic_bom(epic_url, auth):
    """Command-line interface to translate a KiCAD XML file to a BOM."""
    parser = argparse.ArgumentParser(
        description=__doc__, formatter_class=RawDescHelpFormatter
    )
    parser.add_argument(
        "input-file",
        help='Name of XML file generated by KiCad\'s "Generate BOM" command.',
    )
    parser.add_argument(
        "output-file",
        help="Name of output file "
        "that will contain the bill-of-materials (BOM) in "
        "a comma-separated-values (CSV) file.",
    )
    parser.add_argument(
        "-d",
        "--debug",
        action="store_const",
        const=logging.DEBUG,
        dest="log_level",
        default=logging.INFO,
        help="Show debug output.",
    )
    parser.add_argument(
        "-f",
        "--force-overwrite",
        action="store_true",
        help="Force overwriting of existing EPIC BOM "
        "(assembly) part even if the part appears to "
        "have been modified manually.",
    )
    parser.add_argument(
        "--flavor",
        action="append",
        help="Select PCB flavor for which to generate BOM for."
        "  This option may be specified multiple times.",
    )
    parser.add_argument(
        "-q",
        "--quiet",
        action="store_true",
        help="Silence all output except for errors.",
    )
    parser.add_argument(
        "-p",
        "--prefer-vendor",
        nargs="+",
        help="Like --with-vendor-pn, but only output vendor "
        "part numbers for the specified vendor(s).",
    )
    parser.add_argument(
        "-V",
        "--with-vendor-pn",
        help="Include vendor part numbers in the CSV file.",
        action="store_true",
    )
    args = parser.parse_args()

    if args.quiet:
        args.log_level = logging.ERROR

    logging.basicConfig()
    log = logging.getLogger()
    log.setLevel(args.log_level)

    epic_api = EPICAPIClient(epic_url, auth)
    input_file = getattr(args, "input-file")
    try:
        bom = BOM(
            epic_api,
            input_file,
            "eGauge",
            flavors=args.flavor,
            toolname="epic-bom",
        )
        assy, created = bom.save_as_epic_assembly(
            force_update=args.force_overwrite
        )
        if not args.quiet:
            if bom.flavors:
                if len(bom.flavors) > 1:
                    detected_flavors_str = "flavors: "
                else:
                    detected_flavors_str = "flavor: "
                detected_flavors_str += ", ".join(sorted(bom.flavors))
            else:
                detected_flavors_str = "no flavors"
            log.info("this schematic defines %s", detected_flavors_str)

            print(
                "%s part %s (%s %s) with %d components."
                % (
                    "Created" if created else "Updated",
                    format_part_number(assy.id),
                    assy.mfg,
                    assy.mfg_pn,
                    len(bom.comps),
                )
            )

        if args.with_vendor_pn:
            # include all vendors that have relevant parts:
            vendors = []
        elif args.prefer_vendor:
            vendors = []
            for name in args.prefer_vendor:
                v = VendorsCache.find(name, relaxed_match=True)
                if not v:
                    raise Error(f"vendor `{name}' unknown")
                vendors.append(v)
        else:
            vendors = None

        CSVBOM(bom, vendors).save(getattr(args, "output-file"))

    except UnknownFlavorsError as e:
        log.error(
            "Flavor(s) %s are unknown; detected flavors: %s",
            ",".join(e.args[0]),
            ",".join(e.args[1]),
        )
        sys.exit(1)
    except Error as e:
        log.error(e.args)
        traceback.print_exc()
        sys.exit(1)


def epic_footprints(epic_url, auth):
    """Command-line interface to update KiCad schematic files with the
    footprints from EPIC.

    """
    parser = argparse.ArgumentParser(
        description=__doc__, formatter_class=RawDescHelpFormatter
    )
    parser.add_argument(
        "input-file", type=Path, help="Name of KiCad schematic file."
    )
    parser.add_argument(
        "-d",
        "--debug",
        action="store_const",
        const=logging.DEBUG,
        dest="log_level",
        default=logging.INFO,
        help="Show debug output.",
    )
    parser.add_argument(
        "-q",
        "--quiet",
        action="store_const",
        const=logging.ERROR,
        dest="log_level",
        help="Silence all output except for errors.",
    )
    args = parser.parse_args()

    logging.basicConfig()
    log = logging.getLogger()
    log.setLevel(args.log_level)

    epic_api = EPICAPIClient(epic_url, auth)

    path = getattr(args, "input-file")
    if path.suffix == ".sch":
        log.error("Cannot update old (pre v6) KiCad schematics files.")
        sys.exit(1)

    schematics.update_footprints(epic_api, path)
