"""
FastAPI routes for Organizational Compliance Roles.

Manages the 7 standard compliance roles (DSB, GF, IT-Leiter, etc.)
and the document-to-role mapping that determines who reviews which documents.

Endpoints:
  GET    /org-roles              — list roles for tenant/project
  POST   /org-roles              — create/upsert a role
  PUT    /org-roles/{id}         — update role details
  DELETE /org-roles/{id}         — remove a role
  GET    /org-roles/defaults     — 7 standard role definitions
  POST   /org-roles/seed         — seed default roles for a project
  POST   /org-roles/{id}/send-test — send test email to role
  GET    /org-roles/mapping      — document-to-role mapping
  PUT    /org-roles/mapping      — update mapping
"""

import logging
from typing import Optional, List

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import text
from sqlalchemy.orm import Session

from classroom_engine.database import get_db
from .tenant_utils import get_tenant_id as _get_tenant_id
from .db_utils import row_to_dict as _row_to_dict

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/org-roles", tags=["org-roles"])

# =============================================================================
# Standard role definitions
# =============================================================================

DEFAULT_ROLES = [
    {"role_key": "dsb", "role_label": "Datenschutzbeauftragter (DSB)"},
    {"role_key": "gf", "role_label": "Geschaeftsfuehrung"},
    {"role_key": "it_leiter", "role_label": "IT-Leiter / CISO"},
    {"role_key": "hr_leitung", "role_label": "HR-Leitung"},
    {"role_key": "marketing_leitung", "role_label": "Marketing-Leitung"},
    {"role_key": "compliance_beauftragter", "role_label": "Compliance-Beauftragter"},
    {"role_key": "einkauf", "role_label": "Einkauf / Vendor Management"},
]

# =============================================================================
# Schemas
# =============================================================================


class OrgRoleCreate(BaseModel):
    role_key: str
    role_label: str
    person_name: Optional[str] = None
    person_email: Optional[str] = None
    department: Optional[str] = None
    project_id: Optional[str] = None


class OrgRoleUpdate(BaseModel):
    role_label: Optional[str] = None
    person_name: Optional[str] = None
    person_email: Optional[str] = None
    department: Optional[str] = None
    is_active: Optional[bool] = None


class MappingEntry(BaseModel):
    document_type: str
    role_key: str
    is_primary: bool = True


class MappingUpdate(BaseModel):
    entries: List[MappingEntry]


# =============================================================================
# Routes
# =============================================================================


@router.get("")
def list_roles(
    project_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    q = text("""
        SELECT * FROM compliance_org_roles
        WHERE tenant_id = :tid AND (project_id = :pid OR (:pid IS NULL AND project_id IS NULL))
        ORDER BY role_key
    """)
    rows = db.execute(q, {"tid": tenant_id, "pid": project_id}).fetchall()
    return [_row_to_dict(r) for r in rows]


@router.get("/defaults")
def get_defaults():
    return DEFAULT_ROLES


@router.post("")
def create_role(
    body: OrgRoleCreate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    q = text("""
        INSERT INTO compliance_org_roles (tenant_id, project_id, role_key, role_label, person_name, person_email, department)
        VALUES (:tid, :pid, :rk, :rl, :pn, :pe, :dept)
        ON CONFLICT (tenant_id, project_id, role_key) DO UPDATE
        SET role_label = EXCLUDED.role_label,
            person_name = COALESCE(EXCLUDED.person_name, compliance_org_roles.person_name),
            person_email = COALESCE(EXCLUDED.person_email, compliance_org_roles.person_email),
            department = COALESCE(EXCLUDED.department, compliance_org_roles.department),
            updated_at = NOW()
        RETURNING *
    """)
    row = db.execute(q, {
        "tid": tenant_id, "pid": body.project_id, "rk": body.role_key,
        "rl": body.role_label, "pn": body.person_name, "pe": body.person_email,
        "dept": body.department,
    }).fetchone()
    db.commit()
    return _row_to_dict(row)


@router.put("/{role_id}")
def update_role(
    role_id: str,
    body: OrgRoleUpdate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    sets, params = [], {"rid": role_id, "tid": tenant_id}
    for field in ["role_label", "person_name", "person_email", "department", "is_active"]:
        val = getattr(body, field, None)
        if val is not None:
            sets.append(f"{field} = :{field}")
            params[field] = val
    if not sets:
        raise HTTPException(400, "No fields to update")
    sets.append("updated_at = NOW()")
    q = text(f"UPDATE compliance_org_roles SET {', '.join(sets)} WHERE id = :rid AND tenant_id = :tid RETURNING *")
    row = db.execute(q, params).fetchone()
    if not row:
        raise HTTPException(404, "Role not found")
    db.commit()
    return _row_to_dict(row)


@router.delete("/{role_id}")
def delete_role(
    role_id: str,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    q = text("DELETE FROM compliance_org_roles WHERE id = :rid AND tenant_id = :tid")
    result = db.execute(q, {"rid": role_id, "tid": tenant_id})
    db.commit()
    if result.rowcount == 0:
        raise HTTPException(404, "Role not found")
    return {"deleted": True}


@router.post("/seed")
def seed_roles(
    project_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    created = 0
    for role in DEFAULT_ROLES:
        q = text("""
            INSERT INTO compliance_org_roles (tenant_id, project_id, role_key, role_label)
            VALUES (:tid, :pid, :rk, :rl)
            ON CONFLICT (tenant_id, project_id, role_key) DO NOTHING
        """)
        result = db.execute(q, {"tid": tenant_id, "pid": project_id, "rk": role["role_key"], "rl": role["role_label"]})
        created += result.rowcount
    db.commit()
    return {"seeded": created, "total": len(DEFAULT_ROLES)}


@router.post("/{role_id}/send-test")
def send_test_email(
    role_id: str,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    q = text("SELECT * FROM compliance_org_roles WHERE id = :rid AND tenant_id = :tid")
    role = db.execute(q, {"rid": role_id, "tid": tenant_id}).fetchone()
    if not role:
        raise HTTPException(404, "Role not found")
    role_dict = _row_to_dict(role)
    if not role_dict.get("person_email"):
        raise HTTPException(400, "No email configured for this role")

    try:
        from compliance.services.smtp_sender import send_email
        result = send_email(
            recipient=role_dict["person_email"],
            subject=f"[BreakPilot] Test-E-Mail fuer {role_dict['role_label']}",
            body_html=f"""
            <h2>Test-E-Mail</h2>
            <p>Diese E-Mail bestaetigt, dass die Zustellung an die Rolle
            <strong>{role_dict['role_label']}</strong> funktioniert.</p>
            <p>Empfaenger: {role_dict['person_name'] or 'N/A'} ({role_dict['person_email']})</p>
            <p style="color:#888;font-size:12px;">Gesendet von BreakPilot Compliance SDK</p>
            """,
        )
        return {"sent": True, "email": role_dict["person_email"], "result": result}
    except Exception as e:
        logger.error("Failed to send test email: %s", e)
        raise HTTPException(500, f"Email sending failed: {e}")


# =============================================================================
# Document-to-Role Mapping
# =============================================================================


@router.get("/mapping")
def get_mapping(
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    q = text("""
        SELECT * FROM compliance_document_role_mapping
        WHERE tenant_id = :tid
        ORDER BY document_type, role_key
    """)
    rows = db.execute(q, {"tid": tenant_id}).fetchall()
    return [_row_to_dict(r) for r in rows]


@router.put("/mapping")
def update_mapping(
    body: MappingUpdate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    for entry in body.entries:
        q = text("""
            INSERT INTO compliance_document_role_mapping (tenant_id, document_type, role_key, is_primary)
            VALUES (:tid, :dt, :rk, :ip)
            ON CONFLICT (tenant_id, document_type, role_key) DO UPDATE
            SET is_primary = EXCLUDED.is_primary
        """)
        db.execute(q, {"tid": tenant_id, "dt": entry.document_type, "rk": entry.role_key, "ip": entry.is_primary})
    db.commit()
    return {"updated": len(body.entries)}
