from __future__ import annotations

from typing import Any, Dict, List, Sequence
import sys

from SYS.logger import log
from . import _shared as sh

Cmdlet = sh.Cmdlet
CmdletArg = sh.CmdletArg
SharedArgs = sh.SharedArgs


class Metadata(Cmdlet):
    """Unified metadata command with domain + action routing."""

    _ACTION_FLAGS = {
        "add": {"-add", "--add"},
        "delete": {"-delete", "--delete", "-del", "--del"},
        "get": {"-get", "--get"},
        "inspect": {"-inspect", "--inspect", "-info", "--info", "-file", "--file"},
    }

    _DOMAIN_FLAGS = {
        "tag": {"-tag", "--tag", "-tags", "--tags"},
        "url": {"-url", "--url", "-urls", "--urls"},
        "relationship": {
            "-relationship",
            "--relationship",
            "-relationships",
            "--relationships",
            "-rel",
            "--rel",
        },
        "note": {"-note", "--note", "-notes", "--notes"},
        "file": {"-file", "--file"},
    }

    def __init__(self) -> None:
        super().__init__(
            name="metadata",
            summary="Manage metadata domains with one command",
            usage='metadata [-tag|-url|-relationship|-note] (-add|-delete|-get) [args]  OR  metadata -inspect [args]',
            alias=["meta"],
            arg=[
                SharedArgs.QUERY,
                SharedArgs.INSTANCE,
                CmdletArg("-tag", type="flag", required=False, description="Metadata tag domain (default if omitted)"),
                CmdletArg("-url", type="flag", required=False, description="URL metadata domain"),
                CmdletArg("-relationship", type="flag", required=False, description="Relationship metadata domain", alias="rel"),
                CmdletArg("-note", type="flag", required=False, description="Note metadata domain"),
                CmdletArg("-add", type="flag", required=False, description="Add metadata tag value(s)"),
                CmdletArg("-delete", type="flag", required=False, description="Delete metadata tag value(s)", alias="del"),
                CmdletArg("-get", type="flag", required=False, description="Read metadata values for selected domain"),
                CmdletArg("-inspect", type="flag", required=False, description="Inspect file metadata details", alias="info"),
                CmdletArg(
                    "<tag>[,<tag>...]",
                    type="string",
                    required=False,
                    variadic=True,
                    description="Tag values for -add/-delete",
                ),
            ],
            detail=[
                "- Use one action flag: -add, -delete, -get, or -inspect.",
                "- Domain flags: -tag (default), -url, -relationship, -note.",
                "- Examples:",
                "    metadata -url -add <url>",
                "    metadata -url -delete <url>",
                "    metadata -relationship -get",
                "    metadata -note -add -query \"title:lyric text:...\"",
                "- -inspect maps to get-metadata and prints rich metadata details.",
            ],
            exec=self.run,
        )
        self.register()

    @classmethod
    def _extract_parts(
        cls,
        args: Sequence[str],
    ) -> tuple[str | None, str, List[str], List[str], List[str]]:
        matched_actions: List[str] = []
        matched_domains: List[str] = []
        passthrough: List[str] = []

        for token in args or []:
            text = str(token or "")
            lower = text.strip().lower()
            matched = None
            for action_name, variants in cls._ACTION_FLAGS.items():
                if lower in variants:
                    matched = action_name
                    break
            if matched:
                matched_actions.append(matched)
                continue

            matched_domain = None
            for domain_name, variants in cls._DOMAIN_FLAGS.items():
                if lower in variants:
                    matched_domain = domain_name
                    break
            if matched_domain:
                matched_domains.append(matched_domain)
                continue

            passthrough.append(text)

        unique_actions: List[str] = []
        for action in matched_actions:
            if action not in unique_actions:
                unique_actions.append(action)

        unique_domains: List[str] = []
        for domain in matched_domains:
            if domain not in unique_domains:
                unique_domains.append(domain)

        action = unique_actions[0] if len(unique_actions) == 1 else None
        domain = unique_domains[0] if len(unique_domains) == 1 else "tag"
        return action, domain, passthrough, unique_actions, unique_domains

    def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
        action, domain, passthrough_args, seen_actions, seen_domains = self._extract_parts(args)

        if action is None:
            if not seen_actions:
                log(
                    "metadata: missing action flag; choose exactly one of -add, -delete, -get, -inspect",
                    file=sys.stderr,
                )
            else:
                rendered = ", ".join(f"-{name}" for name in seen_actions)
                log(f"metadata: conflicting actions ({rendered}); choose exactly one", file=sys.stderr)
            return 1

        if len(seen_domains) > 1:
            rendered_domains = ", ".join(f"-{name}" for name in seen_domains)
            log(f"metadata: conflicting domains ({rendered_domains}); choose one domain", file=sys.stderr)
            return 1

        if action == "inspect":
            from cmdlet.metadata.inspect import run_inspect_action

            return run_inspect_action(result, passthrough_args, config)

        if domain == "file":
            log("metadata: -file only supports -inspect; use metadata -inspect", file=sys.stderr)
            return 1

        if domain == "tag":
            from cmdlet.metadata.tag import run_tag_action

            return run_tag_action(action, result, passthrough_args, config)

        if domain == "url":
            from cmdlet.metadata.url import run_url_action

            return run_url_action(action, result, passthrough_args, config)

        if domain == "relationship":
            from cmdlet.metadata.relationship import run_relationship_action

            return run_relationship_action(action, result, passthrough_args, config)

        if domain == "note":
            from cmdlet.metadata.note import run_note_action

            return run_note_action(action, result, passthrough_args, config)

        log(f"metadata: unsupported domain '{domain}'", file=sys.stderr)
        return 1


CMDLET = Metadata()
