from __future__ import annotations

import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any

from ..config import ClientConfig, client_dir
from ..history import append_change_markdown, append_history, now_local
from ..knowledge.store import rules_for_task
from ..table import print_table
from .product_feed_optimization import (
    fetch_missing_category_products,
    fetch_missing_title_products,
    fetch_missing_unit_pricing_products,
)


TASK_ID = "check_feed_merchant_quality"
TASK_NAME = "Sprawdzenie feedu i Merchant Center"
DEFAULT_LIMIT = 50


SCOPE = [
    {
        "area": "Atrybuty feedu",
        "check": "Sprawdz braki w danych produktowych widoczne w adsPRO, bez przygotowywania zmian produktow.",
    },
    {
        "area": "Ryzyka Merchant Center",
        "check": "Wypisz kontrole, ktore wymagaja pozniejszej integracji Merchant Center API.",
    },
    {
        "area": "Routing problemow",
        "check": "Rozdziel problemy feedu od zadan optymalizacji tytulow, kategorii Google i unit pricing.",
    },
    {
        "area": "Przygotowanie do Shopping/PMax",
        "check": "Zapisz plan audytu, ktory pozniej moze byc uzyty przez zadania Shopping i PMax.",
    },
]


MERCHANT_CENTER_CHECKS = [
    "swiezosc ostatniego przetworzenia feedu",
    "liczba produktow active, warning i disapproved",
    "procent aktywnych produktow",
    "produkty odrzucone wedlug kodow problemow",
    "landing page errors",
    "broken images",
    "agregacja problemow Merchant Center po issue code",
]


OUT_OF_SCOPE = [
    "optymalizacja tytulow produktow",
    "wybor kategorii Google",
    "uzupelnianie unit pricing",
    "synchronizacja grup reklam PLA_CL1",
    "wdrazanie zmian w adsPRO albo Merchant Center",
]


@dataclass
class FeedMerchantQualityPlan:
    attribute_checks: list[dict]
    merchant_center_checks: list[str]
    scope: list[dict]
    out_of_scope: list[str]
    knowledge_rules: list[dict]
    warnings: list[str]

    def to_dict(self) -> dict:
        return {
            "task": TASK_ID,
            "task_name": TASK_NAME,
            "attribute_checks": self.attribute_checks,
            "merchant_center_checks": self.merchant_center_checks,
            "scope": self.scope,
            "out_of_scope": self.out_of_scope,
            "knowledge_rules": self.knowledge_rules,
            "warnings": self.warnings,
            "changes": [],
        }

    @classmethod
    def from_dict(cls, data: dict) -> "FeedMerchantQualityPlan":
        return cls(
            attribute_checks=data.get("attribute_checks", []),
            merchant_center_checks=data.get("merchant_center_checks", []),
            scope=data.get("scope", []),
            out_of_scope=data.get("out_of_scope", []),
            knowledge_rules=data.get("knowledge_rules", []),
            warnings=data.get("warnings", []),
        )


def product_label(product: dict[str, Any]) -> str:
    return str(
        product.get("title")
        or product.get("default_name")
        or product.get("custom_title")
        or product.get("name")
        or ""
    ).strip()


def sample_products(products: list[dict], max_items: int = 8) -> list[dict]:
    sample = []
    for product in products[:max_items]:
        sample.append(
            {
                "offer_id": str(product.get("offer_id") or product.get("id") or "").strip(),
                "title": product_label(product),
                "brand": str(product.get("brand") or "").strip(),
                "google_product_category": str(
                    product.get("google_product_category") or product.get("google_category") or ""
                ).strip(),
                "custom_label_1": str(product.get("custom_label_1") or "").strip(),
            }
        )
    return sample


def attribute_check(name: str, issue: str, products: list[dict], target_task: str, limit: int) -> dict:
    return {
        "name": name,
        "issue": issue,
        "count": len(products),
        "limit": limit,
        "is_limited": len(products) >= limit,
        "target_task": target_task,
        "sample": sample_products(products),
    }


def fetch_attribute_checks(client_config: ClientConfig, limit: int) -> list[dict]:
    title_products = fetch_missing_title_products(client_config, limit)
    category_products = fetch_missing_category_products(client_config, limit)
    unit_pricing_products = fetch_missing_unit_pricing_products(client_config, limit)
    return [
        attribute_check(
            "Tytuly produktow",
            "Produkty bez zoptymalizowanego tytulu",
            title_products,
            "optimize_product_titles",
            limit,
        ),
        attribute_check(
            "Kategorie Google",
            "Produkty bez kategorii Google",
            category_products,
            "optimize_product_categories",
            limit,
        ),
        attribute_check(
            "Unit pricing",
            "Produkty bez unit pricing",
            unit_pricing_products,
            "fill_product_unit_pricing",
            limit,
        ),
    ]


def build_feed_merchant_quality_plan(
    client_config: ClientConfig,
    global_rules: dict,
) -> FeedMerchantQualityPlan:
    rules = client_config.effective_rules(global_rules, "feed_merchant_quality")
    limit = int(rules.get("limit", DEFAULT_LIMIT))
    warnings = []

    try:
        attribute_checks = fetch_attribute_checks(client_config, limit)
    except Exception as exc:
        attribute_checks = []
        warnings.append(f"Nie udalo sie pobrac danych feedu z adsPRO: {exc}")

    warnings.append(
        "Statusy active/warning/disapproved, issue codes, landing page errors i broken images wymagaja pozniejszej integracji Merchant Center API."
    )
    warnings.append(
        "To zadanie tylko wskazuje problemy feedu. Naprawy tytulow, kategorii Google i unit pricing pozostaja w osobnych zadaniach."
    )
    warnings.append(
        f"Kontrole atrybutow z adsPRO sa pobierane do limitu {limit}; wartosc z plusem oznacza, ze problemow moze byc wiecej."
    )

    knowledge_rules = [
        {
            "id": rule.id,
            "topic": rule.topic,
            "rule_type": rule.rule_type,
            "condition": rule.condition,
            "recommendation": rule.recommendation,
            "risk": rule.risk,
            "source": rule.source,
        }
        for rule in rules_for_task(TASK_ID)
    ]
    if not knowledge_rules:
        warnings.append(
            "Do tego zadania nie przypisano jeszcze regul z bazy wiedzy. "
            "Reguly dotyczace feedu i Merchant Center bedziemy dopisywac osobno po akceptacji uzytkownika."
        )

    return FeedMerchantQualityPlan(
        attribute_checks=attribute_checks,
        merchant_center_checks=MERCHANT_CENTER_CHECKS,
        scope=SCOPE,
        out_of_scope=OUT_OF_SCOPE,
        knowledge_rules=knowledge_rules,
        warnings=warnings,
    )


def md_cell(value: Any) -> str:
    return str(value or "").replace("|", "\\|").replace("\n", " ").strip()


def count_label(check: dict) -> str:
    value = str(check.get("count", 0))
    if check.get("is_limited"):
        return f"{value}+"
    return value


def save_feed_merchant_quality_plan(domain: str, plan: FeedMerchantQualityPlan) -> tuple[Path, Path]:
    ts = now_local()
    base = client_dir(domain) / "plans"
    base.mkdir(parents=True, exist_ok=True)
    stem = f"{ts.strftime('%Y-%m-%d_%H-%M-%S')}_{TASK_ID}"
    json_path = base / f"{stem}.json"
    md_path = base / f"{stem}.md"
    payload = {
        "created_at": ts.isoformat(timespec="seconds"),
        "client": domain,
        **plan.to_dict(),
    }
    json_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")

    lines = [
        "# Plan: Sprawdzenie feedu i Merchant Center",
        "",
        f"Klient: {domain}",
        f"Utworzono: {ts.isoformat(timespec='seconds')}",
        "",
        "## Podsumowanie",
        "",
        f"- Kontrole atrybutow z adsPRO: {len(plan.attribute_checks)}",
        f"- Kontrole Merchant Center do pozniejszej integracji: {len(plan.merchant_center_checks)}",
        f"- Reguly wiedzy przypisane do zadania: {len(plan.knowledge_rules)}",
        "- Zmiany do wdrozenia: 0",
        "",
    ]
    if plan.warnings:
        lines.extend(["## Uwagi", ""])
        lines.extend(f"- {item}" for item in plan.warnings)
        lines.append("")
    lines.extend(["## Zakres zadania", "", "| Obszar | Co sprawdzic |", "| --- | --- |"])
    for row in plan.scope:
        lines.append(f"| {md_cell(row.get('area', ''))} | {md_cell(row.get('check', ''))} |")
    lines.append("")
    lines.extend(["## Poza zakresem tego zadania", ""])
    lines.extend(f"- {item}" for item in plan.out_of_scope)
    lines.append("")
    if plan.attribute_checks:
        lines.extend(
            [
                "## Kontrole atrybutow z adsPRO",
                "",
                "| Obszar | Problem | Liczba | Zadanie naprawcze |",
                "| --- | --- | --- | --- |",
            ]
        )
        for check in plan.attribute_checks:
            lines.append(
                f"| {md_cell(check['name'])} | {md_cell(check['issue'])} | "
                f"{count_label(check)} | {md_cell(check['target_task'])} |"
            )
        lines.append("")
    lines.extend(["## Kontrole Merchant Center do integracji", ""])
    lines.extend(f"- {item}" for item in plan.merchant_center_checks)
    lines.append("")
    if plan.knowledge_rules:
        lines.extend(
            [
                "## Reguly z bazy wiedzy",
                "",
                "| ID | Temat | Rekomendacja | Ryzyko |",
                "| --- | --- | --- | --- |",
            ]
        )
        for rule in plan.knowledge_rules:
            lines.append(
                f"| {md_cell(rule.get('id', ''))} | {md_cell(rule.get('topic', ''))} | "
                f"{md_cell(rule.get('recommendation', ''))} | {md_cell(rule.get('risk', ''))} |"
            )
        lines.append("")
    md_path.write_text("\n".join(lines), encoding="utf-8")
    return json_path, md_path


def print_feed_merchant_quality_plan(plan: FeedMerchantQualityPlan) -> None:
    print("\nPlan sprawdzenia feedu i Merchant Center")
    print_table(
        ["Metryka", "Liczba"],
        [
            ["Kontrole atrybutow", str(len(plan.attribute_checks))],
            ["Kontrole Merchant Center", str(len(plan.merchant_center_checks))],
            ["Reguly wiedzy", str(len(plan.knowledge_rules))],
            ["Zmiany do wdrozenia", "0"],
        ],
    )
    if plan.warnings:
        print("\nUwagi")
        print_table(["Nr", "Uwaga"], [[str(index), item] for index, item in enumerate(plan.warnings, 1)])
    print("\nZakres zadania")
    print_table(
        ["Nr", "Obszar", "Co sprawdzic"],
        [[str(index), row["area"], row["check"]] for index, row in enumerate(plan.scope, 1)],
    )
    print("\nPoza zakresem")
    print_table(["Nr", "Nie analizujemy tutaj"], [[str(index), item] for index, item in enumerate(plan.out_of_scope, 1)])
    if plan.attribute_checks:
        print("\nKontrole atrybutow z adsPRO")
        print_table(
            ["Nr", "Obszar", "Problem", "Liczba", "Zadanie naprawcze"],
            [
                [str(index), check["name"], check["issue"], count_label(check), check["target_task"]]
                for index, check in enumerate(plan.attribute_checks, 1)
            ],
        )
    print("\nKontrole Merchant Center do pozniejszej integracji")
    print_table(
        ["Nr", "Kontrola"],
        [[str(index), item] for index, item in enumerate(plan.merchant_center_checks, 1)],
    )
    if plan.knowledge_rules:
        print("\nReguly z bazy wiedzy")
        print_table(
            ["Nr", "ID", "Temat", "Rekomendacja"],
            [
                [str(index), rule["id"], rule["topic"], rule["recommendation"]]
                for index, rule in enumerate(plan.knowledge_rules[:10], 1)
            ],
        )
        if len(plan.knowledge_rules) > 10:
            print(f"... oraz {len(plan.knowledge_rules) - 10} kolejnych regul")


def print_next_navigation(domain: str) -> None:
    print("\nCo dalej:")
    print(f"1. Lista zadan klienta {domain}")
    print("2. Lista klientow")
    print("3. Zakoncz")
    print("\nKomendy:")
    print(f"1 -> python gads.py analiza-klienta --client {domain}")
    print("2 -> python gads.py analiza-klienta")


def apply_feed_merchant_quality_plan(
    client_config: ClientConfig,
    plan: FeedMerchantQualityPlan,
    show_navigation: bool = True,
) -> None:
    print("\nTo zadanie jest audytem feedu i nie wdraza zmian w adsPRO ani Merchant Center.")
    changes_path = append_change_markdown(client_config.domain, TASK_NAME, [])
    history_path = append_history(
        client_config.domain,
        {
            "task": TASK_NAME,
            "status": "audyt oznaczony jako wykonany",
            "campaign": "",
            "summary": {
                "attribute_checks": len(plan.attribute_checks),
                "merchant_center_checks": len(plan.merchant_center_checks),
                "knowledge_rules": len(plan.knowledge_rules),
                "changes": 0,
            },
        },
    )
    print(f"Historia JSONL: {history_path}")
    print(f"Historia Markdown: {changes_path}")
    if show_navigation:
        print_next_navigation(client_config.domain)


def run_check_feed_merchant_quality(
    client_config: ClientConfig,
    global_rules: dict,
    plan_only: bool = False,
    apply_plan_path: str | None = None,
    confirm_apply: str | None = None,
    show_navigation: bool = True,
) -> None:
    if apply_plan_path:
        if confirm_apply != "TAK":
            print("Do oznaczenia audytu jako wykonanego wymagane jest --confirm-apply TAK.")
            if show_navigation:
                print_next_navigation(client_config.domain)
            return
        plan_data = json.loads(Path(apply_plan_path).read_text(encoding="utf-8"))
        if plan_data.get("client") != client_config.domain:
            print(f"Plan jest dla klienta {plan_data.get('client')}, a wybrano {client_config.domain}.")
            if show_navigation:
                print_next_navigation(client_config.domain)
            return
        plan = FeedMerchantQualityPlan.from_dict(plan_data)
        print_feed_merchant_quality_plan(plan)
        apply_feed_merchant_quality_plan(client_config, plan, show_navigation=show_navigation)
        return

    print(f"\nKlient: {client_config.domain}")
    print("Przygotowuje plan sprawdzenia feedu i Merchant Center...")
    plan = build_feed_merchant_quality_plan(client_config, global_rules)
    print_feed_merchant_quality_plan(plan)
    json_path, md_path = save_feed_merchant_quality_plan(client_config.domain, plan)
    print(f"\nPlan JSON: {json_path}")
    print(f"Plan Markdown: {md_path}")

    append_history(
        client_config.domain,
        {
            "task": TASK_NAME,
            "status": "plan przygotowany",
            "campaign": "",
            "summary": {
                "attribute_checks": len(plan.attribute_checks),
                "merchant_center_checks": len(plan.merchant_center_checks),
                "knowledge_rules": len(plan.knowledge_rules),
                "changes": 0,
            },
        },
    )

    if plan_only:
        print("\nTryb plan-only: zmiany nie zostaly wdrozone.")
        if show_navigation:
            print_next_navigation(client_config.domain)
        return

    print("\nBrak zmian do wdrozenia. To zadanie tworzy plan audytu feedu.")
    if show_navigation:
        print_next_navigation(client_config.domain)
