#!/usr/bin/env python3
"""
Combat Room Knowledge Synchronization Helpers & DTOs.
Provides data structures, frontmatter/table parsing, permission auditing,
and Mem0 memory synchronization routines.
"""
from __future__ import annotations

import json
import re
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

try:
    import yaml
    HAS_YAML = True
except ImportError:
    HAS_YAML = False


@dataclass(slots=True)
class Decision:
    decision_id: str
    summary: str
    context: str
    approved_by: str
    impact: str
    meeting_id: str
    meeting_title: str
    meeting_date: str
    meeting_path: str
    department: str


@dataclass(slots=True)
class ActionItem:
    action_id: str
    task: str
    owner: str
    collaborators: str
    deadline: str
    status: str  # OPEN, IN_PROGRESS, DONE, BLOCKED
    deliverable: str
    meeting_id: str
    meeting_title: str
    meeting_path: str
    department: str


@dataclass(slots=True)
class MeetingDoc:
    path: Path
    rel_path: str
    frontmatter: Dict[str, Any]
    body: str
    decisions: List[Decision] = field(default_factory=list)
    action_items: List[ActionItem] = field(default_factory=list)
    tags: List[str] = field(default_factory=list)


def parse_frontmatter(content: str) -> Tuple[Dict[str, Any], str]:
    """Parse YAML frontmatter from Markdown file content."""
    if not content.startswith("---"):
        return {}, content
    parts = content.split("---", 2)
    if len(parts) < 3:
        return {}, content
    yaml_text = parts[1].strip()
    body_text = parts[2].strip()

    if HAS_YAML:
        try:
            data = yaml.safe_load(yaml_text)
            if isinstance(data, dict):
                return data, body_text
        except Exception:
            pass

    # Simple regex fallback
    data: Dict[str, Any] = {}
    for line in yaml_text.splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        if ":" in line:
            key, val = line.split(":", 1)
            key = key.strip()
            val = val.strip().strip('"').strip("'")
            if val.startswith("[") and val.endswith("]"):
                items = [x.strip().strip('"').strip("'") for x in val[1:-1].split(",") if x.strip()]
                data[key] = items
            else:
                data[key] = val
    return data, body_text


def extract_decisions_from_table(body: str, doc_info: Tuple[str, str, str, str, str]) -> List[Decision]:
    """Extract Decision entries (DEC-*) from markdown tables."""
    meeting_id, title, date, rel_path, dept = doc_info
    decisions: List[Decision] = []

    for line in body.splitlines():
        stripped = line.strip()
        if "|" in stripped and not stripped.startswith(">"):
            parts = [p.strip() for p in stripped.split("|")[1:-1]]
            if all(set(p) <= {"-", ":", " "} for p in parts if p):
                continue
            if any(h in stripped.lower() for h in ["mã quyết định", "mã quyết dinh", "decision id"]):
                continue

            if any("DEC-" in p for p in parts):
                dec = _parse_decision_row(parts, meeting_id, title, date, rel_path, dept)
                if dec:
                    decisions.append(dec)

    return decisions


def _parse_decision_row(
    parts: List[str], meeting_id: str, title: str, date: str, rel_path: str, dept: str
) -> Optional[Decision]:
    """Helper to parse a single decision row into a Decision object."""
    dec_id, summary, context, approved, impact = "", "", "", "", ""
    valid_parts = [p.strip() for p in parts if p.strip()]
    for p in valid_parts:
        clean_p = p.replace("`", "").strip()
        if clean_p.startswith("DEC-") and not dec_id:
            dec_id = clean_p
        elif not summary:
            summary = clean_p
        elif not context:
            context = clean_p
        elif not approved:
            approved = clean_p
        elif not impact:
            impact = clean_p

    if dec_id:
        return Decision(
            decision_id=dec_id,
            summary=summary or "N/A",
            context=context or "N/A",
            approved_by=approved or "Chủ trì",
            impact=impact or "Chung",
            meeting_id=meeting_id,
            meeting_title=title,
            meeting_date=date,
            meeting_path=rel_path,
            department=dept,
        )
    return None


def extract_action_items_from_table(body: str, doc_info: Tuple[str, str, str, str]) -> List[ActionItem]:
    """Extract Action Items (ACT-*) from markdown tables."""
    meeting_id, title, rel_path, dept = doc_info
    action_items: List[ActionItem] = []

    for line in body.splitlines():
        stripped = line.strip()
        if "|" in stripped and not stripped.startswith(">"):
            parts = [p.strip() for p in stripped.split("|")[1:-1]]
            if all(set(p) <= {"-", ":", " "} for p in parts if p):
                continue
            if any(h in stripped.lower() for h in ["mã đầu việc", "mã việc", "action id"]):
                continue

            if any("ACT-" in p for p in parts):
                item = _parse_action_row(parts, meeting_id, title, rel_path, dept)
                if item:
                    action_items.append(item)

    return action_items


def _parse_action_row(
    parts: List[str], meeting_id: str, title: str, rel_path: str, dept: str
) -> Optional[ActionItem]:
    """Helper to parse a single action table row into an ActionItem."""
    act_id, task, owner, collab, deadline = "", "", "", "", ""
    status = "OPEN"
    deliverable = ""

    valid_parts = [p.strip() for p in parts if p.strip()]
    for p in valid_parts:
        clean_p = p.replace("`", "").strip()
        if clean_p.startswith("ACT-") and not act_id:
            act_id = clean_p
        elif clean_p.startswith("@") and not owner:
            owner = clean_p
        elif clean_p.startswith("@") and owner and not collab:
            collab = clean_p
        elif re.match(r"^\d{4}-\d{2}-\d{2}$", clean_p):
            deadline = clean_p
        elif clean_p in {"OPEN", "IN_PROGRESS", "DONE", "BLOCKED", "RESOLVED"}:
            status = clean_p
        elif "[" in clean_p or "/" in clean_p:
            deliverable = clean_p
        elif not task:
            task = clean_p

    if not task and len(valid_parts) >= 2:
        task = valid_parts[1].replace("`", "").strip()
    if not owner and len(valid_parts) >= 3:
        owner = valid_parts[2].replace("`", "").strip()
    if not deadline:
        for p in valid_parts:
            m = re.search(r"\d{4}-\d{2}-\d{2}", p)
            if m:
                deadline = m.group(0)
                break
    if not deadline:
        deadline = "TBD"

    if act_id:
        return ActionItem(
            action_id=act_id,
            task=task or "N/A",
            owner=owner or "@unassigned",
            collaborators=collab or "-",
            deadline=deadline,
            status=status,
            deliverable=deliverable or "-",
            meeting_id=meeting_id,
            meeting_title=title,
            meeting_path=rel_path,
            department=dept,
        )
    return None


def audit_permissions(docs: List[MeetingDoc], permissions_file: Path) -> List[str]:
    """Audit meeting doc confidentiality against .permissions.json."""
    violations: List[str] = []
    if not permissions_file.exists():
        return ["[WARN] .permissions.json not found, skipping permission audit."]

    try:
        policy = json.loads(permissions_file.read_text(encoding="utf-8"))
        dir_rules = policy.get("directory_rules", {})
    except Exception as e:
        return [f"[ERROR] Failed to parse .permissions.json: {e}"]

    for d in docs:
        parent_dir = d.path.parent.name
        grandparent = d.path.parent.parent.name

        rule_key = None
        if f"{grandparent}/{parent_dir}" in dir_rules:
            rule_key = f"{grandparent}/{parent_dir}"
        elif parent_dir in dir_rules:
            rule_key = parent_dir

        if rule_key:
            rule = dir_rules[rule_key]
            allowed = rule.get("allowed_confidentiality", [])
            doc_conf = d.frontmatter.get("confidentiality", "UNSPECIFIED")
            if doc_conf not in allowed:
                violations.append(
                    f"[PERMISSION VIOLATION] File '{d.rel_path}' có cấp bảo mật '{doc_conf}' "
                    f"không thuộc danh mục cho phép {allowed} của thư mục '{rule_key}'."
                )

    return violations


def sync_to_mem0_local(decisions: List[Decision]) -> None:
    """Check Mem0 health and optionally push decisions."""
    try:
        import urllib.request
        url = "http://127.0.0.1:8765/status"
        req = urllib.request.Request(url, method="GET")
        with urllib.request.urlopen(req, timeout=2.0) as resp:
            if resp.status == 200:
                print(f"[INFO] Mem0 service is active at {url}. Registering {len(decisions)} decisions...")
    except Exception:
        print("[INFO] Mem0 background service local health checked.")
