"""
Training Link Service — bridges document review approvals with the Academy.

After a document is approved, checks which roles need training on that
document type and identifies gaps (missing/overdue assignments).

Gracefully handles missing training tables (Go service not migrated yet).
"""

import logging
from typing import Any

from sqlalchemy import text
from sqlalchemy.orm import Session

logger = logging.getLogger(__name__)


class TrainingLinkService:
    """Links document approvals to training requirements."""

    def __init__(self, db: Session) -> None:
        self.db = db

    def _training_tables_exist(self) -> bool:
        """Check if the Go-managed training tables exist."""
        try:
            self.db.execute(text("SELECT 1 FROM training_modules LIMIT 0"))
            return True
        except Exception:
            self.db.rollback()
            return False

    def get_role_codes_for_document(self, tenant_id: str, document_type: str) -> list[dict]:
        """Map document type → org roles → training role codes."""
        try:
            q = text("""
                SELECT m.role_key, t.training_role_code
                FROM compliance_document_role_mapping m
                LEFT JOIN compliance_role_training_mapping t
                  ON t.org_role_key = m.role_key
                  AND (t.tenant_id = :tid OR t.tenant_id = '__default__')
                WHERE m.tenant_id = :tid OR m.tenant_id = '__default__'
                  AND m.document_type = :dt
            """)
            rows = self.db.execute(q, {"tid": tenant_id, "dt": document_type}).fetchall()
            return [{"role_key": r.role_key, "training_role_code": r.training_role_code} for r in rows]
        except Exception as e:
            logger.warning("Failed to get role codes: %s", e)
            return []

    def get_training_requirements(self, tenant_id: str, document_type: str) -> dict[str, Any]:
        """Get training modules required for roles associated with a document type."""
        if not self._training_tables_exist():
            return {
                "academy_available": False,
                "message": "Academy noch nicht eingerichtet. Training-Module werden nach Aktivierung automatisch verknuepft.",
                "requirements": [],
            }

        role_mappings = self.get_role_codes_for_document(tenant_id, document_type)
        if not role_mappings:
            return {"academy_available": True, "message": "Keine Rollen-Zuordnung fuer diesen Dokumenttyp.", "requirements": []}

        role_codes = [r["training_role_code"] for r in role_mappings if r.get("training_role_code")]
        if not role_codes:
            return {"academy_available": True, "message": "Keine Training-Codes konfiguriert.", "requirements": []}

        try:
            placeholders = ",".join(f":rc{i}" for i in range(len(role_codes)))
            params: dict[str, Any] = {"tid": tenant_id}
            for i, rc in enumerate(role_codes):
                params[f"rc{i}"] = rc

            q = text(f"""
                SELECT tm.role_code, m.module_code, m.title, m.description,
                       m.frequency_type, m.duration_minutes, tm.is_mandatory
                FROM training_matrix tm
                JOIN training_modules m ON m.id = tm.module_id
                WHERE tm.tenant_id = :tid AND tm.role_code IN ({placeholders})
                  AND m.is_active = TRUE
                ORDER BY tm.role_code, m.sort_order
            """)
            rows = self.db.execute(q, params).fetchall()
            reqs = [dict(r._mapping) for r in rows]
            return {"academy_available": True, "requirements": reqs, "total": len(reqs)}
        except Exception as e:
            logger.warning("Failed to query training requirements: %s", e)
            return {"academy_available": True, "requirements": [], "error": str(e)}

    def check_training_gaps(
        self, tenant_id: str, document_type: str, project_id: str | None = None,
    ) -> dict[str, Any]:
        """Check which persons assigned to roles have outstanding training."""
        if not self._training_tables_exist():
            return {"academy_available": False, "gaps": [], "total_gaps": 0}

        role_mappings = self.get_role_codes_for_document(tenant_id, document_type)
        if not role_mappings:
            return {"academy_available": True, "gaps": [], "total_gaps": 0}

        gaps = []
        for rm in role_mappings:
            role_key = rm["role_key"]
            role_code = rm.get("training_role_code")
            if not role_code:
                continue

            # Get person assigned to this role
            where = "tenant_id = :tid AND role_key = :rk"
            params: dict[str, Any] = {"tid": tenant_id, "rk": role_key}
            if project_id:
                where += " AND (project_id = :pid OR project_id IS NULL)"
                params["pid"] = project_id

            try:
                person = self.db.execute(text(
                    f"SELECT person_name, person_email, role_label FROM compliance_org_roles WHERE {where} LIMIT 1"
                ), params).fetchone()
            except Exception:
                continue

            if not person or not person.person_name:
                continue

            # Get required modules for this role code
            try:
                modules = self.db.execute(text("""
                    SELECT m.id, m.module_code, m.title FROM training_matrix tm
                    JOIN training_modules m ON m.id = tm.module_id
                    WHERE tm.tenant_id = :tid AND tm.role_code = :rc AND m.is_active = TRUE AND tm.is_mandatory = TRUE
                """), {"tid": tenant_id, "rc": role_code}).fetchall()
            except Exception:
                continue

            for mod in modules:
                # Check if assignment exists and is completed
                try:
                    assignment = self.db.execute(text("""
                        SELECT status, progress_percent FROM training_assignments
                        WHERE tenant_id = :tid AND module_id = :mid AND user_email = :email
                        ORDER BY created_at DESC LIMIT 1
                    """), {"tid": tenant_id, "mid": mod.id, "email": person.person_email}).fetchone()
                except Exception:
                    assignment = None

                if not assignment or assignment.status not in ("completed", "passed"):
                    gaps.append({
                        "person_name": person.person_name,
                        "person_email": person.person_email,
                        "role": person.role_label,
                        "role_key": role_key,
                        "module_code": mod.module_code,
                        "module_title": mod.title,
                        "status": assignment.status if assignment else "nicht_begonnen",
                        "progress": assignment.progress_percent if assignment else 0,
                    })

        return {"academy_available": True, "gaps": gaps, "total_gaps": len(gaps)}
