import logging

from fastapi import APIRouter, Depends, File, Form, HTTPException, Response, UploadFile, status
from sqlalchemy.orm import Session
from starlette.requests import Request

from app.core.rbac import get_current_active_user, get_user_permission_names, require_permission
from app.db.database import get_db
from app.models.customer import Customer, CustomerContact
from app.models.user import User
from app.repositories.customer_repository import CustomerRepository
from app.schemas.customer import (
    CustomerContactCreate,
    CustomerContactResponse,
    CustomerContactUpdate,
    CustomerCreate,
    CustomerResponse,
    CustomerUpdate,
)
from app.schemas.customer_import import (
    CustomerImportCommitResponse,
    CustomerImportPreviewResponse,
    ImportMode,
)
from app.services.audit_service import sanitize, write_audit_log
from app.services.customer_import_service import CustomerImportService

logger = logging.getLogger(__name__)

router = APIRouter(
    prefix="/customers",
    tags=["Customers"],
)

MAX_IMPORT_SIZE_BYTES = 5 * 1024 * 1024


async def read_import_file(file: UploadFile) -> bytes:
    content = await file.read(MAX_IMPORT_SIZE_BYTES + 1)
    if len(content) > MAX_IMPORT_SIZE_BYTES:
        raise HTTPException(
            status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
            detail="CSV-Datei darf maximal 5 MB groß sein",
        )
    if not content:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="CSV-Datei ist leer",
        )
    return content


def get_customer_or_404(db: Session, customer_id: int) -> Customer:
    customer = CustomerRepository.get_by_id(db, customer_id)
    if customer is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Kunde nicht gefunden",
        )
    return customer


def get_contact_or_404(db: Session, customer_id: int, contact_id: int) -> CustomerContact:
    contact = CustomerRepository.get_contact_by_id(db, customer_id, contact_id)
    if contact is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Ansprechpartner nicht gefunden",
        )
    return contact


def ensure_unique_customer_number(
    db: Session,
    customer_number: str,
    customer_id: int | None = None,
) -> None:
    conflict = CustomerRepository.find_number_conflict(
        db,
        customer_number=customer_number,
        exclude_customer_id=customer_id,
    )
    if conflict is not None:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Kundennummer ist bereits vergeben",
        )


@router.get("", response_model=list[CustomerResponse])
@router.get("/", response_model=list[CustomerResponse], include_in_schema=False)
def get_customers(
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.read")),
):
    logger.info("customers.list", extra={"actor_user_id": current_user.id})
    return CustomerRepository.get_all(db)


@router.get("/{customer_id}", response_model=CustomerResponse)
def get_customer(
    customer_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.read")),
):
    logger.info(
        "customers.detail",
        extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
    )
    return get_customer_or_404(db, customer_id)


@router.post("", response_model=CustomerResponse, status_code=status.HTTP_201_CREATED)
@router.post(
    "/",
    response_model=CustomerResponse,
    status_code=status.HTTP_201_CREATED,
    include_in_schema=False,
)
def create_customer(
    customer: CustomerCreate,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.create")),
):
    ensure_unique_customer_number(db, customer.customer_number)
    logger.info("customers.create", extra={"actor_user_id": current_user.id})
    created_customer = CustomerRepository.create(db, customer)
    write_audit_log(
        db,
        action="customers.create",
        entity_type="customers",
        entity_id=created_customer.id,
        entity_label=created_customer.company_name,
        actor=current_user,
        request=request,
        after_data=created_customer,
    )
    return created_customer


@router.post("/import/preview", response_model=CustomerImportPreviewResponse)
async def preview_customer_import(
    mode: ImportMode = Form(...),
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.read")),
):
    logger.info("customers.import.preview", extra={"actor_user_id": current_user.id, "mode": mode})
    content = await read_import_file(file)
    try:
        return CustomerImportService.preview(db, content, mode)
    except ValueError as exc:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc


@router.post("/import/commit", response_model=CustomerImportCommitResponse)
async def commit_customer_import(
    request: Request,
    mode: ImportMode = Form(...),
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    permissions = get_user_permission_names(current_user)
    required_permissions = {"customers.create"} if mode == "create_only" else {"customers.update"}
    if mode == "upsert":
        required_permissions = {"customers.create", "customers.update"}
    if not required_permissions.issubset(permissions):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Keine Berechtigung")

    logger.info("customers.import.commit", extra={"actor_user_id": current_user.id, "mode": mode})
    content = await read_import_file(file)
    try:
        return CustomerImportService.commit(db, content, mode, actor=current_user, request=request)
    except ValueError as exc:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc


@router.put("/{customer_id}", response_model=CustomerResponse)
def update_customer(
    customer_id: int,
    customer: CustomerUpdate,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.update")),
):
    db_customer = get_customer_or_404(db, customer_id)
    before_data = sanitize(db_customer)
    ensure_unique_customer_number(db, customer.customer_number, customer_id)
    logger.info(
        "customers.update",
        extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
    )
    updated_customer = CustomerRepository.update(db, db_customer, customer)
    write_audit_log(
        db,
        action="customers.update",
        entity_type="customers",
        entity_id=updated_customer.id,
        entity_label=updated_customer.company_name,
        actor=current_user,
        request=request,
        before_data=before_data,
        after_data=updated_customer,
    )
    return updated_customer


@router.delete("/{customer_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_customer(
    customer_id: int,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.delete")),
):
    db_customer = get_customer_or_404(db, customer_id)
    before_data = sanitize(db_customer)
    entity_label = db_customer.company_name
    logger.info(
        "customers.delete",
        extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
    )
    CustomerRepository.delete(db, db_customer)
    write_audit_log(
        db,
        action="customers.delete",
        entity_type="customers",
        entity_id=customer_id,
        entity_label=entity_label,
        actor=current_user,
        request=request,
        before_data=before_data,
    )
    return Response(status_code=status.HTTP_204_NO_CONTENT)


@router.get("/{customer_id}/contacts", response_model=list[CustomerContactResponse])
def get_customer_contacts(
    customer_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.read")),
):
    get_customer_or_404(db, customer_id)
    logger.info(
        "customers.contacts.list",
        extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
    )
    return CustomerRepository.get_contacts(db, customer_id)


@router.post(
    "/{customer_id}/contacts",
    response_model=CustomerContactResponse,
    status_code=status.HTTP_201_CREATED,
)
def create_customer_contact(
    customer_id: int,
    contact: CustomerContactCreate,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.update")),
):
    customer = get_customer_or_404(db, customer_id)
    logger.info(
        "customers.contacts.create",
        extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
    )
    created_contact = CustomerRepository.create_contact(db, customer_id, contact)
    write_audit_log(
        db,
        action="customer_contacts.create",
        entity_type="customer_contacts",
        entity_id=created_contact.id,
        entity_label=f"{created_contact.first_name} {created_contact.last_name}".strip(),
        actor=current_user,
        request=request,
        after_data=created_contact,
        metadata={"customer_id": customer_id, "customer_label": customer.company_name},
    )
    return created_contact


@router.put("/{customer_id}/contacts/{contact_id}", response_model=CustomerContactResponse)
def update_customer_contact(
    customer_id: int,
    contact_id: int,
    contact: CustomerContactUpdate,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.update")),
):
    customer = get_customer_or_404(db, customer_id)
    db_contact = get_contact_or_404(db, customer_id, contact_id)
    before_data = sanitize(db_contact)
    logger.info(
        "customers.contacts.update",
        extra={
            "actor_user_id": current_user.id,
            "target_customer_id": customer_id,
            "target_contact_id": contact_id,
        },
    )
    updated_contact = CustomerRepository.update_contact(db, db_contact, contact)
    write_audit_log(
        db,
        action="customer_contacts.update",
        entity_type="customer_contacts",
        entity_id=updated_contact.id,
        entity_label=f"{updated_contact.first_name} {updated_contact.last_name}".strip(),
        actor=current_user,
        request=request,
        before_data=before_data,
        after_data=updated_contact,
        metadata={"customer_id": customer_id, "customer_label": customer.company_name},
    )
    return updated_contact


@router.delete("/{customer_id}/contacts/{contact_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_customer_contact(
    customer_id: int,
    contact_id: int,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_permission("customers.update")),
):
    customer = get_customer_or_404(db, customer_id)
    db_contact = get_contact_or_404(db, customer_id, contact_id)
    before_data = sanitize(db_contact)
    entity_label = f"{db_contact.first_name} {db_contact.last_name}".strip()
    logger.info(
        "customers.contacts.delete",
        extra={
            "actor_user_id": current_user.id,
            "target_customer_id": customer_id,
            "target_contact_id": contact_id,
        },
    )
    CustomerRepository.delete_contact(db, db_contact)
    write_audit_log(
        db,
        action="customer_contacts.delete",
        entity_type="customer_contacts",
        entity_id=contact_id,
        entity_label=entity_label,
        actor=current_user,
        request=request,
        before_data=before_data,
        metadata={"customer_id": customer_id, "customer_label": customer.company_name},
    )
    return Response(status_code=status.HTTP_204_NO_CONTENT)
