"""
Admin Activity Type Mappings Management - v9d Phase 1b

CRUD operations for activity_type_mappings (learnable system).
"""
import logging
from typing import Optional
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel

from db import get_db, get_cursor, r2d
from auth import require_admin

router = APIRouter(prefix="/api/admin/activity-mappings", tags=["admin", "activity-mappings"])
logger = logging.getLogger(__name__)


class ActivityMappingCreate(BaseModel):
    activity_type: str
    training_type_id: int
    profile_id: Optional[str] = None
    source: str = 'admin'


class ActivityMappingUpdate(BaseModel):
    training_type_id: Optional[int] = None
    profile_id: Optional[str] = None
    source: Optional[str] = None


@router.get("")
def list_activity_mappings(
    profile_id: Optional[str] = None,
    global_only: bool = False,
    session: dict = Depends(require_admin)
):
    """
    Get all activity type mappings.

    Filters:
    - profile_id: Show only mappings for specific profile
    - global_only: Show only global mappings (profile_id IS NULL)
    """
    with get_db() as conn:
        cur = get_cursor(conn)

        query = """
            SELECT m.id, m.activity_type, m.training_type_id, m.profile_id, m.source,
                   m.created_at, m.updated_at,
                   t.name_de as training_type_name_de,
                   t.category, t.subcategory, t.icon
            FROM activity_type_mappings m
            JOIN training_types t ON m.training_type_id = t.id
        """

        conditions = []
        params = []

        if global_only:
            conditions.append("m.profile_id IS NULL")
        elif profile_id:
            conditions.append("m.profile_id = %s")
            params.append(profile_id)

        if conditions:
            query += " WHERE " + " AND ".join(conditions)

        query += " ORDER BY m.activity_type"

        cur.execute(query, params)
        rows = cur.fetchall()

    return [r2d(r) for r in rows]


@router.get("/{mapping_id}")
def get_activity_mapping(mapping_id: int, session: dict = Depends(require_admin)):
    """Get single activity mapping by ID."""
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("""
            SELECT m.id, m.activity_type, m.training_type_id, m.profile_id, m.source,
                   m.created_at, m.updated_at,
                   t.name_de as training_type_name_de,
                   t.category, t.subcategory
            FROM activity_type_mappings m
            JOIN training_types t ON m.training_type_id = t.id
            WHERE m.id = %s
        """, (mapping_id,))
        row = cur.fetchone()

    if not row:
        raise HTTPException(404, "Mapping not found")

    return r2d(row)


@router.post("")
def create_activity_mapping(data: ActivityMappingCreate, session: dict = Depends(require_admin)):
    """
    Create new activity type mapping.

    Note: Duplicate (activity_type, profile_id) will fail with 409 Conflict.
    """
    with get_db() as conn:
        cur = get_cursor(conn)

        try:
            cur.execute("""
                INSERT INTO activity_type_mappings
                  (activity_type, training_type_id, profile_id, source)
                VALUES (%s, %s, %s, %s)
                RETURNING id
            """, (
                data.activity_type,
                data.training_type_id,
                data.profile_id,
                data.source
            ))

            new_id = cur.fetchone()['id']

            logger.info(f"[ADMIN] Mapping created: {data.activity_type} → training_type_id {data.training_type_id} (profile: {data.profile_id})")

        except Exception as e:
            if 'unique_activity_type_per_profile' in str(e):
                raise HTTPException(409, f"Mapping for '{data.activity_type}' already exists (profile: {data.profile_id})")
            raise HTTPException(400, f"Failed to create mapping: {str(e)}")

    return {"id": new_id, "message": "Mapping created"}


@router.put("/{mapping_id}")
def update_activity_mapping(
    mapping_id: int,
    data: ActivityMappingUpdate,
    session: dict = Depends(require_admin)
):
    """Update existing activity type mapping."""
    with get_db() as conn:
        cur = get_cursor(conn)

        # Build update query dynamically
        updates = []
        values = []

        if data.training_type_id is not None:
            updates.append("training_type_id = %s")
            values.append(data.training_type_id)
        if data.profile_id is not None:
            updates.append("profile_id = %s")
            values.append(data.profile_id)
        if data.source is not None:
            updates.append("source = %s")
            values.append(data.source)

        if not updates:
            raise HTTPException(400, "No fields to update")

        updates.append("updated_at = CURRENT_TIMESTAMP")
        values.append(mapping_id)

        cur.execute(f"""
            UPDATE activity_type_mappings
            SET {', '.join(updates)}
            WHERE id = %s
        """, values)

        if cur.rowcount == 0:
            raise HTTPException(404, "Mapping not found")

        logger.info(f"[ADMIN] Mapping updated: {mapping_id}")

    return {"id": mapping_id, "message": "Mapping updated"}


@router.delete("/{mapping_id}")
def delete_activity_mapping(mapping_id: int, session: dict = Depends(require_admin)):
    """
    Delete activity type mapping.

    This will cause future imports to NOT auto-assign training type for this activity_type.
    Existing activities with this mapping remain unchanged.
    """
    with get_db() as conn:
        cur = get_cursor(conn)

        cur.execute("DELETE FROM activity_type_mappings WHERE id = %s", (mapping_id,))

        if cur.rowcount == 0:
            raise HTTPException(404, "Mapping not found")

        logger.info(f"[ADMIN] Mapping deleted: {mapping_id}")

    return {"message": "Mapping deleted"}


@router.get("/stats/coverage")
def get_mapping_coverage(session: dict = Depends(require_admin)):
    """
    Get statistics about mapping coverage.

    Returns how many activities are mapped vs unmapped across all profiles.
    """
    with get_db() as conn:
        cur = get_cursor(conn)

        cur.execute("""
            SELECT
                COUNT(*) as total_activities,
                COUNT(training_type_id) as mapped_activities,
                COUNT(*) - COUNT(training_type_id) as unmapped_activities,
                COUNT(DISTINCT activity_type) as unique_activity_types,
                COUNT(DISTINCT CASE WHEN training_type_id IS NULL THEN activity_type END) as unmapped_types
            FROM activity_log
        """)
        stats = r2d(cur.fetchone())

    return stats
