import json
from typing import Optional, Dict, Any

from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel
from sqlalchemy.orm import Session as OrmSession

from app.api.deps import get_db, get_current_user, require_admin, verify_project_access
from app.models.catalog import UserAccount, ProjectMember
from app.schemas.common import PaginatedResponse
from app.schemas.project import (
    ProjectCreate,
    ProjectUpdate,
    ProjectResponse,
    MemberAdd,
    MemberUpdate,
    MemberResponse,
)
from app.services.project_service import ProjectService


class ActivityResponse(BaseModel):
    id: str
    actor_id: str
    actor_username: str = ""
    action: str
    resource_type: str
    resource_id: Optional[str] = None
    project_id: Optional[str] = None
    detail_json: str
    ip_address: Optional[str] = None
    created_at: str

    model_config = {"from_attributes": True}


def _enrich_activity(a, db: OrmSession) -> dict:
    d = ActivityResponse.model_validate(a).model_dump()
    user = db.query(UserAccount).filter(UserAccount.id == a.actor_id).first()
    d["actor_username"] = user.display_name if user else a.actor_id
    return d


router = APIRouter(prefix="/api/v1/projects", tags=["projects"])
activity_router = APIRouter(prefix="/api/v1/activities", tags=["activities"])


# ── projects ──────────────────────────────────────────────────

@router.get("/", response_model=PaginatedResponse[ProjectResponse])
def list_projects(
    page: int = 1,
    per_page: int = 20,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    items, total = service.list_projects(current_user, page, per_page)
    def to_response(p):
        d = ProjectResponse.model_validate(p).model_dump()
        creator = db.query(UserAccount).filter(UserAccount.id == p.created_by).first()
        d["created_by"] = creator.display_name if creator else p.created_by
        member = db.query(ProjectMember).filter(
            ProjectMember.project_id == p.id, ProjectMember.user_id == current_user.id
        ).first()
        d["my_role"] = member.role if member else ("admin" if current_user.role == "admin" else None)
        d["member_count"] = db.query(ProjectMember).filter(ProjectMember.project_id == p.id).count()
        return d

    return PaginatedResponse(
        items=[to_response(p) for p in items],
        total=total,
        page=page,
        per_page=per_page,
    )


@router.post("/", response_model=ProjectResponse)
def create_project(
    body: ProjectCreate,
    request: Request,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    ip = request.client.host if request.client else None
    project = service.create_project(body.name, body.description or "", current_user, ip)
    return project


@router.get("/{project_id}")
def get_project(
    project_id: str,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    return service.get_project(project_id, current_user)


@router.patch("/{project_id}", response_model=ProjectResponse)
def update_project(
    project_id: str,
    body: ProjectUpdate,
    request: Request,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    ip = request.client.host if request.client else None
    updates = body.model_dump(exclude_none=True)
    return service.update_project(project_id, updates, current_user, ip)


@router.delete("/{project_id}", response_model=ProjectResponse)
def delete_project(
    project_id: str,
    request: Request,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    ip = request.client.host if request.client else None
    return service.delete_project(project_id, current_user, ip)


# ── members ───────────────────────────────────────────────────

def _enrich_member(m, db: OrmSession) -> dict:
    user = db.query(UserAccount).filter(UserAccount.id == m.user_id).first()
    d = MemberResponse.model_validate(m).model_dump()
    d["username"] = user.username if user else m.user_id
    d["display_name"] = user.display_name if user else m.user_id
    return d


@router.get("/{project_id}/members", response_model=list[MemberResponse])
def list_members(
    project_id: str,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    members = service.list_members(project_id, current_user)
    return [_enrich_member(m, db) for m in members]


@router.post("/{project_id}/members", response_model=MemberResponse)
def add_member(
    project_id: str,
    body: MemberAdd,
    request: Request,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    ip = request.client.host if request.client else None
    m = service.add_member(project_id, body.user_id, body.role, current_user, ip)
    return _enrich_member(m, db)


@router.patch("/{project_id}/members/{user_id}", response_model=MemberResponse)
def update_member_role(
    project_id: str,
    user_id: str,
    body: MemberUpdate,
    request: Request,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    ip = request.client.host if request.client else None
    m = service.update_member_role(project_id, user_id, body.role, current_user, ip)
    return _enrich_member(m, db)


@router.delete("/{project_id}/members/{user_id}")
def remove_member(
    project_id: str,
    user_id: str,
    request: Request,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    ip = request.client.host if request.client else None
    service.remove_member(project_id, user_id, current_user, ip)
    return {"ok": True}


# ── project activities ────────────────────────────────────────

@router.get("/{project_id}/activities", response_model=PaginatedResponse[ActivityResponse])
def project_activities(
    project_id: str,
    page: int = 1,
    per_page: int = 20,
    action: Optional[str] = None,
    actor_id: Optional[str] = None,
    date_from: Optional[str] = None,
    date_to: Optional[str] = None,
    current_user: UserAccount = Depends(get_current_user),
    db: OrmSession = Depends(get_db),
):
    # Check access first
    service = ProjectService(db)
    project = service._get_project(project_id)
    service._check_access(project, current_user)
    items, total = service.list_activities(
        page=page, per_page=per_page, project_id=project_id,
        action=action, actor_id=actor_id, date_from=date_from, date_to=date_to,
    )
    return PaginatedResponse(
        items=[_enrich_activity(a, db) for a in items],
        total=total,
        page=page,
        per_page=per_page,
    )


# ── global activities (admin only) ───────────────────────────

@activity_router.get("/", response_model=PaginatedResponse[ActivityResponse])
def all_activities(
    page: int = 1,
    per_page: int = 20,
    action: Optional[str] = None,
    actor_id: Optional[str] = None,
    date_from: Optional[str] = None,
    date_to: Optional[str] = None,
    admin: UserAccount = Depends(require_admin),
    db: OrmSession = Depends(get_db),
):
    service = ProjectService(db)
    items, total = service.list_activities(
        page=page, per_page=per_page,
        action=action, actor_id=actor_id, date_from=date_from, date_to=date_to,
    )
    return PaginatedResponse(
        items=[_enrich_activity(a, db) for a in items],
        total=total,
        page=page,
        per_page=per_page,
    )


# ── LLM 모델 설정 ──

@router.get("/{project_id}/llm-config")
def get_llm_config(
    project_id: str = Depends(verify_project_access),
    db: OrmSession = Depends(get_db),
    current_user: UserAccount = Depends(get_current_user),
):
    """프로젝트별 LLM 모델 설정 조회 (기본값 포함)."""
    from app.models.project import ProjectSettings
    from app.modules.llm.llm_router import PIPELINE_STEPS, AVAILABLE_MODELS, get_step_config

    ps = db.query(ProjectSettings).filter(ProjectSettings.project_id == project_id).first()
    project_config = {}
    if ps and ps.llm_config_json:
        try:
            project_config = json.loads(ps.llm_config_json)
        except (json.JSONDecodeError, TypeError):
            pass

    steps = []
    for step_key, step_info in PIPELINE_STEPS.items():
        current = get_step_config(step_key, project_config)
        steps.append({
            "step": step_key,
            "label": step_info["label"],
            "category": step_info["category"],
            "provider": current["provider"],
            "model": current["model"],
            "is_default": step_key not in project_config,
        })

    return {
        "steps": steps,
        "available_models": AVAILABLE_MODELS,
    }


class LLMConfigUpdate(BaseModel):
    config: Dict[str, Dict[str, str]]  # { step_key: { provider, model } }


@router.put("/{project_id}/llm-config")
def update_llm_config(
    body: LLMConfigUpdate,
    project_id: str = Depends(verify_project_access),
    db: OrmSession = Depends(get_db),
    current_user: UserAccount = Depends(get_current_user),
):
    """프로젝트별 LLM 모델 설정 저장."""
    from app.models.project import ProjectSettings
    from datetime import datetime, timezone

    ps = db.query(ProjectSettings).filter(ProjectSettings.project_id == project_id).first()
    now = datetime.now(timezone.utc).isoformat()
    if not ps:
        import uuid
        ps = ProjectSettings(
            id=str(uuid.uuid4()),
            project_id=project_id,
            llm_config_json=json.dumps(body.config, ensure_ascii=False),
            updated_at=now,
        )
        db.add(ps)
    else:
        ps.llm_config_json = json.dumps(body.config, ensure_ascii=False)
        ps.updated_at = now
    db.commit()

    return {"ok": True, "message": "LLM 설정이 저장되었습니다"}
