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

from app.core.database import get_db
from app.core.models import SystemConfig, User
from app.core.security import require_admin
from app.services.email_service import send_email
from app.services.invoice_pdf import (
    AVAILABLE_TEMPLATE_VARIABLES,
    DEFAULT_INVOICE_TEMPLATE,
    DEFAULT_INVOICE_EMAIL_BODY_TEMPLATE,
    DEFAULT_INVOICE_EMAIL_SUBJECT_TEMPLATE,
    DEFAULT_PAYMENT_METHODS,
)
from app.core.config import get_ai_config as runtime_ai_config

router = APIRouter(prefix="/api/config", tags=["config"])


# ===== Helpers =====

def _get_secret_masked(db: Session, key_name: str) -> str | None:
    row = db.get(SystemConfig, key_name)
    if not row:
        return None
    if row.is_secret and row.key_value:
        return "******"
    return row.key_value


def _upsert_secret(db: Session, key_name: str, value: str, is_secret: bool = False):
    row = db.get(SystemConfig, key_name)
    if row:
        row.key_value = value
        row.is_secret = is_secret
    else:
        row = SystemConfig(key_name=key_name, key_value=value, is_secret=is_secret)
        db.add(row)
    db.commit()


def _get_config_value(db: Session, key_name: str, default: str = "") -> str:
    row = db.get(SystemConfig, key_name)
    if row and row.key_value is not None:
        return row.key_value
    return default


# ===== System Basics =====

SYSTEM_DEFAULTS = {
    "system_name": "ERP Control",
    "system_subtitle": "IT service operations",
    "company_name": "IT Service Company",
    "default_currency": "NZD",
    "timezone": "Pacific/Auckland",
    "date_format": "YYYY-MM-DD",
}


class SystemSettingsResponse(BaseModel):
    system_name: str
    system_subtitle: str
    company_name: str
    default_currency: str
    timezone: str
    date_format: str


class SystemSettingsUpdate(BaseModel):
    system_name: str = Field(min_length=1, max_length=80)
    system_subtitle: str = Field(max_length=120)
    company_name: str = Field(max_length=120)
    default_currency: str = Field(min_length=3, max_length=10)
    timezone: str = Field(max_length=80)
    date_format: str = Field(max_length=40)


def _get_system_settings(db: Session) -> SystemSettingsResponse:
    return SystemSettingsResponse(
        **{
            key: _get_config_value(db, key, default)
            for key, default in SYSTEM_DEFAULTS.items()
        }
    )


@router.get("/system", response_model=SystemSettingsResponse)
def get_system_settings(db: Session = Depends(get_db)):
    return _get_system_settings(db)


@router.put("/system", response_model=SystemSettingsResponse)
def update_system_settings(
    data: SystemSettingsUpdate,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    for key, value in data.model_dump().items():
        _upsert_secret(db, key, value.strip(), is_secret=False)
    return _get_system_settings(db)


# ===== SMTP =====

class SMTPConfigResponse(BaseModel):
    model_config = {"from_attributes": True}

    smtp_host: str | None = None
    smtp_port: int | None = None
    smtp_user: str | None = None
    smtp_password: str | None = None
    smtp_from_name: str | None = None
    smtp_from_email: str | None = None
    smtp_use_tls: bool | None = None


class SMTPConfigUpdate(BaseModel):
    smtp_host: str | None = None
    smtp_port: int | None = None
    smtp_user: str | None = None
    smtp_password: str | None = None
    smtp_from_name: str | None = None
    smtp_from_email: str | None = None
    smtp_use_tls: bool | None = None


class SMTPTestRequest(BaseModel):
    to_email: str


smtp_keys = ["smtp_host", "smtp_port", "smtp_user", "smtp_password",
             "smtp_from_name", "smtp_from_email", "smtp_use_tls"]


@router.get("/smtp", response_model=SMTPConfigResponse)
def get_smtp_config(
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    result = {}
    for key in smtp_keys:
        if key == "smtp_use_tls":
            raw = _get_secret_masked(db, "smtp_use_tls")
            result["smtp_use_tls"] = raw.lower() == "true" if raw else True
        elif key == "smtp_port":
            raw = _get_secret_masked(db, key)
            result["smtp_port"] = int(raw) if raw else None
        else:
            result[key] = _get_secret_masked(db, key)
    return SMTPConfigResponse(**result)


@router.put("/smtp", response_model=SMTPConfigResponse)
def update_smtp_config(
    data: SMTPConfigUpdate,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    update_map = data.model_dump(exclude_unset=True)
    for key, value in update_map.items():
        is_secret = key == "smtp_password"
        if key == "smtp_use_tls":
            value = "true" if value else "false"
        if key == "smtp_port" and value is not None:
            value = str(value)
        _upsert_secret(db, key, str(value) if value is not None else "", is_secret=is_secret)
    db.commit()
    return get_smtp_config(current_user=current_user, db=db)


@router.post("/smtp/test")
async def test_smtp_config(
    data: SMTPTestRequest,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    result = await send_email(
        to_email=data.to_email,
        subject="ERP SMTP Test",
        body="This is a test email from ERP.",
    )
    if not result["success"]:
        raise HTTPException(status_code=400, detail=result["error"])
    return {"success": True, "message": "Test email sent"}


# ===== Telegram =====

class TelegramConfigResponse(BaseModel):
    bot_token: str | None
    chat_id: str | None = None


class TelegramConfigUpdate(BaseModel):
    bot_token: str | None = None
    chat_id: str | None = None


@router.get("/telegram", response_model=TelegramConfigResponse)
def get_telegram_config(
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    return TelegramConfigResponse(
        bot_token=_get_secret_masked(db, "telegram_bot_token"),
        chat_id=_get_config_value(db, "telegram_chat_id"),
    )


@router.put("/telegram", response_model=TelegramConfigResponse)
def update_telegram_config(
    data: TelegramConfigUpdate,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    if data.bot_token is not None:
        _upsert_secret(db, "telegram_bot_token", data.bot_token, is_secret=True)
    if data.chat_id is not None:
        _upsert_secret(db, "telegram_chat_id", data.chat_id, is_secret=False)
    return get_telegram_config(current_user=current_user, db=db)


# ===== AI =====

class AIConfigResponse(BaseModel):
    ai_model: str | None = None
    ai_api_key: str | None = None


class AIConfigUpdate(BaseModel):
    ai_model: str | None = None
    ai_api_key: str | None = None


@router.get("/ai", response_model=AIConfigResponse)
def get_ai_config(
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    config = runtime_ai_config()
    api_key = _get_secret_masked(db, "ai_api_key")
    return AIConfigResponse(
        ai_model=config["model"],
        ai_api_key=api_key,
    )


@router.put("/ai", response_model=AIConfigResponse)
def update_ai_config(
    data: AIConfigUpdate,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    if data.ai_model is not None:
        _upsert_secret(db, "ai_model", data.ai_model, is_secret=False)
    if data.ai_api_key is not None:
        _upsert_secret(db, "ai_api_key", data.ai_api_key, is_secret=True)
    return get_ai_config(current_user=current_user, db=db)


# ===== Invoice Template =====

class InvoiceTemplateConfigResponse(BaseModel):
    template_html: str
    email_subject_template: str
    email_body_template: str
    available_variables: list[str] = Field(default_factory=list)


class InvoiceTemplateConfigUpdate(BaseModel):
    template_html: str
    email_subject_template: str
    email_body_template: str


@router.get("/invoice-template", response_model=InvoiceTemplateConfigResponse)
def get_invoice_template_config(
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    return InvoiceTemplateConfigResponse(
        template_html=_get_config_value(db, "invoice_template_html", DEFAULT_INVOICE_TEMPLATE),
        email_subject_template=_get_config_value(
            db,
            "invoice_email_subject_template",
            DEFAULT_INVOICE_EMAIL_SUBJECT_TEMPLATE,
        ),
        email_body_template=_get_config_value(
            db,
            "invoice_email_body_template",
            DEFAULT_INVOICE_EMAIL_BODY_TEMPLATE,
        ),
        available_variables=list(AVAILABLE_TEMPLATE_VARIABLES),
    )


@router.put("/invoice-template", response_model=InvoiceTemplateConfigResponse)
def update_invoice_template_config(
    data: InvoiceTemplateConfigUpdate,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    _upsert_secret(db, "invoice_template_html", data.template_html, is_secret=False)
    _upsert_secret(db, "invoice_email_subject_template", data.email_subject_template, is_secret=False)
    _upsert_secret(db, "invoice_email_body_template", data.email_body_template, is_secret=False)
    return get_invoice_template_config(current_user=current_user, db=db)


# ===== Payment Methods =====

class PaymentMethodsConfigResponse(BaseModel):
    payment_methods: list[str] = Field(default_factory=list)


class PaymentMethodsConfigUpdate(BaseModel):
    payment_methods: list[str] = Field(default_factory=list)


def _normalize_payment_methods(methods: list[str]) -> list[str]:
    normalized: list[str] = []
    for method in methods:
        value = method.strip()
        if value:
            normalized.append(value)
    return normalized or list(DEFAULT_PAYMENT_METHODS)


@router.get("/payment-methods", response_model=PaymentMethodsConfigResponse)
def get_payment_methods_config(
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    raw = _get_config_value(db, "invoice_payment_methods", ",".join(DEFAULT_PAYMENT_METHODS))
    methods = _normalize_payment_methods(
        [part for chunk in raw.splitlines() for part in chunk.split(",")]
    )
    return PaymentMethodsConfigResponse(payment_methods=methods)


@router.put("/payment-methods", response_model=PaymentMethodsConfigResponse)
def update_payment_methods_config(
    data: PaymentMethodsConfigUpdate,
    current_user: User = Depends(require_admin),
    db: Session = Depends(get_db),
):
    methods = _normalize_payment_methods(data.payment_methods)
    _upsert_secret(db, "invoice_payment_methods", "\n".join(methods), is_secret=False)
    return PaymentMethodsConfigResponse(payment_methods=methods)
