#!/usr/bin/python3
# Copyright (c) Turnkey GNU/Linux <admin@turnkeylinux.org>
#
# this file is part of tkldev-detective.
#
# tkldev-detective is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# tkldev-detective is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# tkldev-detective. If not, see <https://www.gnu.org/licenses/>.
from argparse import ArgumentParser
from os.path import relpath, abspath
from typing import Generator
import sys

from libtkldet import locator, modman, report, colors
import libtkldet
import libtkldet.error
import libtkldet.classifier
import libtkldet.linter


def perform_lint(
    path: str, dump_tags: bool, skip_lint: bool
) -> Generator[report.Report, None, None]:
    libtkldet.initialize(path)

    root = locator.get_appliance_root(path)

    for path in locator.locator(path):
        item = libtkldet.classifier.FileItem(
            value=path,
            _tags={},
            relpath=relpath(path, start=root),
            abspath=abspath(path),
        )
        for classifier in all_classifiers:
            classifier.classify(item)
        if dump_tags:
            item.pretty_print()
        if not skip_lint:
            for linter in all_linters:
                gen = linter.do_check(item)
                if gen:
                    yield from gen


if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument("--color", choices=["always", "never", "auto"], default="auto")
    subparsers = parser.add_subparsers(dest="action")

    list_parser = subparsers.add_parser("list")
    list_parser.add_argument("list_item", choices=["linters", "classifiers", "all"])
    lint_parser = subparsers.add_parser("lint")
    lint_parser.add_argument(
        "-t",
        "--dump-tags",
        action="store_true",
        help="show tags for each file before linting",
    )
    lint_parser.add_argument(
        "-s",
        "--skip-lint",
        action="store_true",
        help="don't actually perform lint, only classification",
    )
    lint_parser.add_argument(
        "target",
        help="appliance name, path to appliance or path to file inside appliance",
    )

    args = parser.parse_args()

    if args.color == "auto":
        colors.set_colors_enabled(sys.stdout.isatty())
    else:
        colors.set_colors_enabled(args.color == "always")

    modman.load_modules()

    all_classifiers = libtkldet.classifier.get_weighted_classifiers()
    all_linters = libtkldet.linter.get_weighted_linters()

    linters_by_name = {l.__class__.__name__: l for l in all_linters}
    classifiers_by_name = {c.__class__.__name__: c for c in all_classifiers}

    if args.action == "list":
        if args.list_item in ("linters", "all"):
            for item in all_linters:
                print("linter", item.__class__.__name__)
        if args.list_item in ("classifiers", "all"):
            for item in all_classifiers:
                print("classifier", item.__class__.__name__)

    elif args.action == "lint":
        try:
            for report in report.filter_all_reports(
                perform_lint(args.target, args.dump_tags, args.skip_lint)
            ):
                print("\n|   ".join(report.format().split("\n")))
                print()
        except libtkldet.error.PlanNotFound as e:
            print(
                colors.RED
                + "error: "
                + colors.RESET
                + "unable to find required plan: "
                + e.args[0]
            )
            sys.exit(1)
        except libtkldet.error.TKLDevDetectiveError as e:
            print(colors.RED + "error: " + colors.RESET + e.args[0])
            sys.exit(1)
