import uuid
from pathlib import Path
from typing import Annotated

from fastapi import APIRouter, Depends, File, UploadFile

from app.application.exceptions import ValidationError
from app.application.services.settings_service import SettingsService
from app.domain.entities.settings import CompanyProfile, GeneralSetting
from app.domain.entities.user_registration import UserRegistration
from app.presentation.auth_dependencies import get_current_user
from app.presentation.company_dependencies import get_validated_company_id_query
from app.presentation.dependencies import get_settings_service
from app.presentation.schemas.common import MessageResponse
from app.presentation.schemas.settings import (
    CompanyProfileOptionsResponse,
    CompanyProfileResponse,
    CompanyProfileUpdate,
    GeneralSettingOptionsResponse,
    GeneralSettingResponse,
    GeneralSettingUpdate,
    PublicBrandingResponse,
)

router = APIRouter(prefix="/settings", tags=["Settings"])
public_router = APIRouter(prefix="/settings", tags=["Settings"])

CompanyId = Annotated[str, Depends(get_validated_company_id_query)]


@public_router.get(
    "/branding",
    response_model=PublicBrandingResponse,
    summary="Public system branding for the login page",
)
async def get_public_branding(
    service: SettingsService = Depends(get_settings_service),
):
    setting = await service.get_public_branding()
    return PublicBrandingResponse(
        site_name=setting.site_name,
        site_tagline=setting.site_tagline,
        detail_description=setting.detail_description,
        logo_path=setting.logo_path,
    )

_STATIC_ROOT = Path(__file__).resolve().parents[4] / "static"
_LOGO_ALLOWED_EXT = {".png", ".jpg", ".jpeg", ".svg"}
_LOGO_MAX_BYTES = 2 * 1024 * 1024


def _to_response(setting: GeneralSetting) -> GeneralSettingResponse:
    data = setting.model_dump()
    data["logo_filename"] = setting.logo_filename
    return GeneralSettingResponse.model_validate(data)


def _to_profile_response(profile: CompanyProfile) -> CompanyProfileResponse:
    data = profile.model_dump()
    data["logo_filename"] = profile.logo_filename
    return CompanyProfileResponse.model_validate(data)


def _delete_logo_file(logo_path: str | None) -> None:
    if not logo_path or not logo_path.startswith("/static/"):
        return
    file_path = _STATIC_ROOT / logo_path.removeprefix("/static/")
    if file_path.is_file():
        file_path.unlink()


async def _save_logo(company_id: str, logo: UploadFile, folder: str = "settings") -> str:
    filename = logo.filename or ""
    ext = Path(filename).suffix.lower()
    if ext not in _LOGO_ALLOWED_EXT:
        raise ValidationError("Logo must be PNG, JPG, or SVG")
    content = await logo.read()
    if len(content) > _LOGO_MAX_BYTES:
        raise ValidationError("Logo must be 2MB or smaller")
    dest_dir = _STATIC_ROOT / folder / company_id
    dest_dir.mkdir(parents=True, exist_ok=True)
    stored_name = f"{uuid.uuid4().hex}{ext}"
    (dest_dir / stored_name).write_bytes(content)
    return f"/static/{folder}/{company_id}/{stored_name}"


@router.get(
    "/general/options",
    response_model=GeneralSettingOptionsResponse,
    summary="General settings dropdown options",
)
async def get_general_options(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    await service.get_general(current_user, company_id)
    return GeneralSettingOptionsResponse.model_validate(service.list_options())


@router.get(
    "/general",
    response_model=GeneralSettingResponse,
    summary="Get general settings",
)
async def get_general_settings(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    setting = await service.get_general(current_user, company_id)
    return _to_response(setting)


@router.put(
    "/general",
    response_model=GeneralSettingResponse,
    summary="Save general settings",
)
async def update_general_settings(
    company_id: CompanyId,
    payload: GeneralSettingUpdate,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    setting = await service.update_general(
        current_user, company_id, payload.model_dump(exclude_unset=True)
    )
    return _to_response(setting)


@router.post(
    "/general/logo",
    response_model=GeneralSettingResponse,
    summary="Upload general settings logo",
)
async def upload_general_logo(
    company_id: CompanyId,
    logo: UploadFile = File(description="PNG, JPG, or SVG — max 2MB"),
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    existing = await service.get_general(current_user, company_id)
    logo_path = await _save_logo(company_id, logo)
    setting = await service.update_general(
        current_user, company_id, {"logo_path": logo_path}
    )
    _delete_logo_file(existing.logo_path)
    return _to_response(setting)


@router.delete(
    "/general/logo",
    response_model=MessageResponse,
    summary="Delete general settings logo",
)
async def delete_general_logo(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    existing = await service.get_general(current_user, company_id)
    await service.delete_logo(current_user, company_id)
    _delete_logo_file(existing.logo_path)
    return MessageResponse(message="Logo deleted")


@router.get(
    "/company-profile/options",
    response_model=CompanyProfileOptionsResponse,
    summary="Company profile dropdown options",
)
async def get_company_profile_options(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    await service.get_company_profile(current_user, company_id)
    return CompanyProfileOptionsResponse.model_validate(
        service.list_company_profile_options()
    )


@router.get(
    "/company-profile",
    response_model=CompanyProfileResponse,
    summary="Get company profile",
)
async def get_company_profile(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    profile = await service.get_company_profile(current_user, company_id)
    return _to_profile_response(profile)


@router.put(
    "/company-profile",
    response_model=CompanyProfileResponse,
    summary="Save company profile",
)
async def update_company_profile(
    company_id: CompanyId,
    payload: CompanyProfileUpdate,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    profile = await service.update_company_profile(
        current_user, company_id, payload.model_dump(exclude_unset=True)
    )
    return _to_profile_response(profile)


@router.post(
    "/company-profile/logo",
    response_model=CompanyProfileResponse,
    summary="Upload company profile logo",
)
async def upload_company_profile_logo(
    company_id: CompanyId,
    logo: UploadFile = File(description="PNG, JPG, or SVG — max 2MB"),
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    existing = await service.get_company_profile(current_user, company_id)
    logo_path = await _save_logo(company_id, logo, folder="company-profiles")
    profile = await service.update_company_profile(
        current_user, company_id, {"logo_path": logo_path}
    )
    if existing.logo_path and existing.logo_path.startswith("/static/settings/"):
        _delete_logo_file(existing.logo_path)
    elif existing.logo_path and existing.logo_path.startswith("/static/company-profiles/"):
        _delete_logo_file(existing.logo_path)
    return _to_profile_response(profile)


@router.delete(
    "/company-profile/logo",
    response_model=MessageResponse,
    summary="Delete company profile logo",
)
async def delete_company_profile_logo(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: SettingsService = Depends(get_settings_service),
):
    existing = await service.get_company_profile(current_user, company_id)
    await service.delete_company_profile_logo(current_user, company_id)
    if existing.logo_path and (
        existing.logo_path.startswith("/static/settings/")
        or existing.logo_path.startswith("/static/company-profiles/")
    ):
        _delete_logo_file(existing.logo_path)
    return MessageResponse(message="Logo deleted")
