from datetime import datetime
from typing import Any
from uuid import UUID

from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.v1.dependencies.auth import get_current_user, require_role
from src.core.exceptions import NotFoundException
from src.domain.entities import ERPSystemEntity, UserRole
from src.domain.interfaces import IERPSystemRepository
from src.infrastructure.database.repositories import ERPSystemRepository
from src.infrastructure.database.session import get_db_session
from src.services.auth.security import TokenData

router = APIRouter(prefix="/erp-systems", tags=["ERP Systems"])


class ERPSystemCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=255)
    erp_type: str
    version: str | None = None
    base_url: str | None = None
    auth_config: dict[str, Any] | None = None
    metadata: dict[str, Any] | None = None


class ERPSystemUpdateRequest(BaseModel):
    name: str | None = Field(None, min_length=1, max_length=255)
    version: str | None = None
    base_url: str | None = None
    auth_config: dict[str, Any] | None = None
    status: str | None = None
    metadata: dict[str, Any] | None = None


class ERPSystemResponse(BaseModel):
    id: UUID
    name: str
    erp_type: str
    version: str | None
    base_url: str | None
    auth_config: dict[str, Any] | None
    status: str
    metadata: dict[str, Any] | None
    created_at: datetime | None
    updated_at: datetime | None


class ERPSystemListResponse(BaseModel):
    items: list[ERPSystemResponse]
    total: int
    offset: int
    limit: int


def _entity_to_response(e: ERPSystemEntity) -> ERPSystemResponse:
    return ERPSystemResponse(
        id=e.id, name=e.name, erp_type=e.erp_type, version=e.version,
        base_url=e.base_url, auth_config=e.auth_config, status=e.status,
        metadata=e.metadata_, created_at=e.created_at, updated_at=e.updated_at,
    )


def _get_repo(session: AsyncSession) -> IERPSystemRepository:
    return ERPSystemRepository(session)


@router.get("", response_model=ERPSystemListResponse)
async def list_erp_systems(
    erp_type: str | None = None,
    offset: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(get_current_user),
):
    repo = _get_repo(session)
    entities, total = await repo.list_erp_systems(erp_type=erp_type, offset=offset, limit=limit)
    return ERPSystemListResponse(items=[_entity_to_response(e) for e in entities], total=total, offset=offset, limit=limit)


@router.get("/{erp_id}", response_model=ERPSystemResponse)
async def get_erp_system(
    erp_id: UUID,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(get_current_user),
):
    repo = _get_repo(session)
    entity = await repo.get_by_id(erp_id)
    if not entity:
        raise NotFoundException("ERP System", str(erp_id))
    return _entity_to_response(entity)


@router.post("", response_model=ERPSystemResponse, status_code=201)
async def create_erp_system(
    body: ERPSystemCreateRequest,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    repo = _get_repo(session)
    entity = ERPSystemEntity(
        name=body.name, erp_type=body.erp_type, version=body.version,
        base_url=body.base_url, auth_config=body.auth_config,
        metadata_=body.metadata,
    )
    created = await repo.create(entity)
    return _entity_to_response(created)


@router.put("/{erp_id}", response_model=ERPSystemResponse)
async def update_erp_system(
    erp_id: UUID,
    body: ERPSystemUpdateRequest,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    repo = _get_repo(session)
    entity = await repo.get_by_id(erp_id)
    if not entity:
        raise NotFoundException("ERP System", str(erp_id))

    update_data = body.model_dump(exclude_unset=True)
    if "metadata" in update_data:
        entity.metadata_ = update_data.pop("metadata")
    for key, value in update_data.items():
        setattr(entity, key, value)

    updated = await repo.update(entity)
    return _entity_to_response(updated)


@router.delete("/{erp_id}", status_code=204)
async def delete_erp_system(
    erp_id: UUID,
    session: AsyncSession = Depends(get_db_session),
    current_user: TokenData = Depends(require_role(UserRole.ADMIN)),
):
    repo = _get_repo(session)
    deleted = await repo.delete(erp_id)
    if not deleted:
        raise NotFoundException("ERP System", str(erp_id))
