from datetime import datetime
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, EmailStr, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import get_current_user
from app.db.session import get_db
from app.models.datasource import DataSource
from app.models.system_setting import SystemSetting
from app.models.user import User
from app.services.scheduler import sync_datasource_job

router = APIRouter()

DEFAULT_SETTINGS = {
    "system": {
        "system_name": "智能星球",
        "refresh_interval": 60,
        "auto_refresh": True,
        "data_retention_days": 30,
        "max_concurrent_tasks": 5,
    },
    "notifications": {
        "email_enabled": False,
        "email_address": "",
        "critical_alerts": True,
        "warning_alerts": True,
        "daily_summary": False,
    },
    "security": {
        "session_timeout": 60,
        "max_login_attempts": 5,
        "password_policy": "medium",
    },
}


class SystemSettingsUpdate(BaseModel):
    system_name: str = "智能星球"
    refresh_interval: int = Field(default=60, ge=10, le=3600)
    auto_refresh: bool = True
    data_retention_days: int = Field(default=30, ge=1, le=3650)
    max_concurrent_tasks: int = Field(default=5, ge=1, le=50)


class NotificationSettingsUpdate(BaseModel):
    email_enabled: bool = False
    email_address: Optional[EmailStr] = None
    critical_alerts: bool = True
    warning_alerts: bool = True
    daily_summary: bool = False


class SecuritySettingsUpdate(BaseModel):
    session_timeout: int = Field(default=60, ge=5, le=1440)
    max_login_attempts: int = Field(default=5, ge=1, le=20)
    password_policy: str = Field(default="medium")


class CollectorSettingsUpdate(BaseModel):
    is_active: bool
    priority: str = Field(default="P1")
    frequency_minutes: int = Field(default=60, ge=1, le=10080)


def merge_with_defaults(category: str, payload: Optional[dict]) -> dict:
    merged = DEFAULT_SETTINGS[category].copy()
    if payload:
        merged.update(payload)
    return merged


async def get_setting_record(db: AsyncSession, category: str) -> Optional[SystemSetting]:
    result = await db.execute(select(SystemSetting).where(SystemSetting.category == category))
    return result.scalar_one_or_none()


async def get_setting_payload(db: AsyncSession, category: str) -> dict:
    record = await get_setting_record(db, category)
    return merge_with_defaults(category, record.payload if record else None)


async def save_setting_payload(db: AsyncSession, category: str, payload: dict) -> dict:
    record = await get_setting_record(db, category)
    if record is None:
        record = SystemSetting(category=category, payload=payload)
        db.add(record)
    else:
        record.payload = payload

    await db.commit()
    await db.refresh(record)
    return merge_with_defaults(category, record.payload)


def format_frequency_label(minutes: int) -> str:
    if minutes % 1440 == 0:
        return f"{minutes // 1440}d"
    if minutes % 60 == 0:
        return f"{minutes // 60}h"
    return f"{minutes}m"


def serialize_collector(datasource: DataSource) -> dict:
    return {
        "id": datasource.id,
        "name": datasource.name,
        "source": datasource.source,
        "module": datasource.module,
        "priority": datasource.priority,
        "frequency_minutes": datasource.frequency_minutes,
        "frequency": format_frequency_label(datasource.frequency_minutes),
        "is_active": datasource.is_active,
        "last_run_at": datasource.last_run_at.isoformat() if datasource.last_run_at else None,
        "last_status": datasource.last_status,
        "next_run_at": datasource.next_run_at.isoformat() if datasource.next_run_at else None,
    }


@router.get("/system")
async def get_system_settings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    return {"system": await get_setting_payload(db, "system")}


@router.put("/system")
async def update_system_settings(
    settings: SystemSettingsUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    payload = await save_setting_payload(db, "system", settings.model_dump())
    return {"status": "updated", "system": payload}


@router.get("/notifications")
async def get_notification_settings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    return {"notifications": await get_setting_payload(db, "notifications")}


@router.put("/notifications")
async def update_notification_settings(
    settings: NotificationSettingsUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    payload = await save_setting_payload(db, "notifications", settings.model_dump())
    return {"status": "updated", "notifications": payload}


@router.get("/security")
async def get_security_settings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    return {"security": await get_setting_payload(db, "security")}


@router.put("/security")
async def update_security_settings(
    settings: SecuritySettingsUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    payload = await save_setting_payload(db, "security", settings.model_dump())
    return {"status": "updated", "security": payload}


@router.get("/collectors")
async def get_collector_settings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(select(DataSource).order_by(DataSource.module, DataSource.id))
    datasources = result.scalars().all()
    return {"collectors": [serialize_collector(datasource) for datasource in datasources]}


@router.put("/collectors/{datasource_id}")
async def update_collector_settings(
    datasource_id: int,
    settings: CollectorSettingsUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    datasource = await db.get(DataSource, datasource_id)
    if not datasource:
        raise HTTPException(status_code=404, detail="Data source not found")

    datasource.is_active = settings.is_active
    datasource.priority = settings.priority
    datasource.frequency_minutes = settings.frequency_minutes
    await db.commit()
    await db.refresh(datasource)
    await sync_datasource_job(datasource.id)
    return {"status": "updated", "collector": serialize_collector(datasource)}


@router.get("")
async def get_all_settings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(select(DataSource).order_by(DataSource.module, DataSource.id))
    datasources = result.scalars().all()
    return {
        "system": await get_setting_payload(db, "system"),
        "notifications": await get_setting_payload(db, "notifications"),
        "security": await get_setting_payload(db, "security"),
        "collectors": [serialize_collector(datasource) for datasource in datasources],
        "generated_at": datetime.utcnow().isoformat() + "Z",
    }
