from __future__ import annotations

import csv
from dataclasses import dataclass
from io import StringIO
from typing import Any, Iterable


PRODUCT_LIBRARY_HEADERS = [
    "library_id",
    "category",
    "subcategory",
    "product_or_class",
    "active_ingredient_or_device",
    "presentation_or_concentration",
    "template_use",
    "field_keys",
    "regulatory_source",
    "verification_status",
    "default_behavior",
    "required_documentation",
    "verification_steps",
    "source_url",
    "notes",
]

DEFAULT_PROFILE_HEADERS = [
    "profile_id",
    "profile_family",
    "field_key",
    "default_value",
    "default_layer",
    "default_allowed",
    "verification_status",
    "notes",
]

APPROVED_PRODUCT_STATUS = "VERIFIED_ACTIVE"
NON_PRODUCT_PROTOCOL_STATUSES = {
    "PHYSICIAN_VERIFY_EACH_CASE",
    "VERIFY_CLINIC_PROTOCOL",
}
REQUIRED_VERIFICATION_FIELDS = [
    "verified_by",
    "verified_date",
    "regulatory_source",
    "source_url",
    "DIN_or_licence_number",
    "manufacturer",
    "status",
    "last_checked",
    "clinic_stocked_yes_no",
    "approved_for_default_yes_no",
]
PRODUCT_VERIFICATION_WORKFLOW_FIELDS = [
    "verified_by",
    "verified_date",
    "DIN_or_licence_number",
    "manufacturer",
    "status",
    "monograph_or_label_url",
    "last_checked",
    "review_interval",
    "clinic_stocked_yes_no",
    "approved_for_default_yes_no",
]


@dataclass(frozen=True)
class ApprovalFinding:
    item_id: str
    item_type: str
    status: str
    approved_for_default: bool
    reason: str


def row_to_dict(row: list[Any], headers: list[str]) -> dict[str, Any]:
    result = {header: row[index] if index < len(row) else "" for index, header in enumerate(headers)}
    extra = row[len(headers) :]
    if extra:
        result["_extra"] = extra
    return result


def product_rows(data: dict[str, Any]) -> list[dict[str, Any]]:
    return [
        row_to_dict(row, PRODUCT_LIBRARY_HEADERS)
        for row in data.get("product_library", {}).get("product_rows", [])
    ]


def default_profile_rows(data: dict[str, Any]) -> list[dict[str, Any]]:
    return [
        row_to_dict(row, DEFAULT_PROFILE_HEADERS)
        for row in data.get("product_library", {}).get("product_default_profiles", [])
    ]


def missing_required_verification(row: dict[str, Any]) -> list[str]:
    return [
        field
        for field in REQUIRED_VERIFICATION_FIELDS
        if str(row.get(field, "")).strip() == ""
    ]


def product_approval_finding(row: dict[str, Any]) -> ApprovalFinding:
    status = str(row.get("verification_status", "")).strip()
    item_id = str(row.get("library_id", "")).strip()
    missing = missing_required_verification(row)
    explicit_default_approval = str(row.get("approved_for_default_yes_no", "")).strip().upper()

    if status != APPROVED_PRODUCT_STATUS:
        return ApprovalFinding(
            item_id=item_id,
            item_type="product",
            status=status,
            approved_for_default=False,
            reason=f"status is {status or 'blank'}, not {APPROVED_PRODUCT_STATUS}",
        )

    if missing:
        return ApprovalFinding(
            item_id=item_id,
            item_type="product",
            status=status,
            approved_for_default=False,
            reason="missing verification fields: " + "; ".join(missing),
        )

    if explicit_default_approval != "YES":
        return ApprovalFinding(
            item_id=item_id,
            item_type="product",
            status=status,
            approved_for_default=False,
            reason="approved_for_default_yes_no is not YES",
        )

    return ApprovalFinding(
        item_id=item_id,
        item_type="product",
        status=status,
        approved_for_default=True,
        reason="verified active with complete default approval fields",
    )


def default_profile_approval_finding(row: dict[str, Any]) -> ApprovalFinding:
    status = str(row.get("verification_status", "")).strip()
    item_id = f"{row.get('profile_id', '')}:{row.get('field_key', '')}"
    allowed = str(row.get("default_allowed", "")).strip().upper()

    if allowed == "NO":
        return ApprovalFinding(
            item_id=item_id,
            item_type="default_profile",
            status=status,
            approved_for_default=False,
            reason="default_allowed is NO",
        )

    if status in NON_PRODUCT_PROTOCOL_STATUSES:
        return ApprovalFinding(
            item_id=item_id,
            item_type="default_profile",
            status=status,
            approved_for_default=False,
            reason="requires physician/protocol review before approval",
        )

    if status != APPROVED_PRODUCT_STATUS:
        return ApprovalFinding(
            item_id=item_id,
            item_type="default_profile",
            status=status,
            approved_for_default=False,
            reason=f"status is {status or 'blank'}, not {APPROVED_PRODUCT_STATUS}",
        )

    return ApprovalFinding(
        item_id=item_id,
        item_type="default_profile",
        status=status,
        approved_for_default=True,
        reason="profile status permits default approval",
    )


def approval_findings(data: dict[str, Any]) -> list[ApprovalFinding]:
    findings = [product_approval_finding(row) for row in product_rows(data)]
    findings.extend(default_profile_approval_finding(row) for row in default_profile_rows(data))
    return findings


def approval_summary(data: dict[str, Any]) -> dict[str, int]:
    findings = approval_findings(data)
    return {
        "items": len(findings),
        "approved_for_default": sum(1 for finding in findings if finding.approved_for_default),
        "blocked_or_pending": sum(1 for finding in findings if not finding.approved_for_default),
    }


def findings_to_csv(findings: Iterable[ApprovalFinding]) -> str:
    buffer = StringIO()
    writer = csv.writer(buffer)
    writer.writerow(["item_id", "item_type", "status", "approved_for_default", "reason"])
    for finding in findings:
        writer.writerow(
            [
                finding.item_id,
                finding.item_type,
                finding.status,
                "YES" if finding.approved_for_default else "NO",
                finding.reason,
            ]
        )
    return buffer.getvalue()


def product_library_rows_for_output(data: dict[str, Any]) -> list[dict[str, Any]]:
    rows = product_rows(data)
    for row in rows:
        for field in PRODUCT_VERIFICATION_WORKFLOW_FIELDS:
            row.setdefault(field, "")
    return rows


def default_profile_rows_for_output(data: dict[str, Any]) -> list[dict[str, Any]]:
    rows = default_profile_rows(data)
    findings = {
        finding.item_id: finding for finding in (default_profile_approval_finding(row) for row in rows)
    }
    for row in rows:
        item_id = f"{row.get('profile_id', '')}:{row.get('field_key', '')}"
        finding = findings[item_id]
        row["approved_for_default_current"] = "YES" if finding.approved_for_default else "NO"
        row["approval_reason"] = finding.reason
    return rows
