from __future__ import annotations

from io import BytesIO

from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
from fastapi import Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

from dependencies import get_import_ingestion_service, require_roles
from models import User
from schemas.imports import (
    ImportCommitRequest,
    ProjectImportCommitResponse,
    ProjectImportPreviewResponse,
    ScenarioImportCommitResponse,
    ScenarioImportPreviewResponse,
)
from services.importers import ImportIngestionService, UnsupportedImportFormat

router = APIRouter(prefix="/imports", tags=["Imports"])
templates = Jinja2Templates(directory="templates")

MANAGE_ROLES = ("project_manager", "admin")


@router.get(
    "/ui",
    response_class=HTMLResponse,
    include_in_schema=False,
    name="imports.ui",
)
def import_dashboard(
    request: Request,
    _: User = Depends(require_roles(*MANAGE_ROLES)),
) -> HTMLResponse:
    return templates.TemplateResponse(
        request,
        "imports/ui.html",
        {
            "title": "Imports",
        },
    )


async def _read_upload_file(upload: UploadFile) -> BytesIO:
    content = await upload.read()
    if not content:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Uploaded file is empty.",
        )
    return BytesIO(content)


@router.post(
    "/projects/preview",
    response_model=ProjectImportPreviewResponse,
    status_code=status.HTTP_200_OK,
)
async def preview_project_import(
    file: UploadFile = File(...,
                            description="Project import file (CSV or Excel)"),
    _: User = Depends(require_roles(*MANAGE_ROLES)),
    ingestion_service: ImportIngestionService = Depends(
        get_import_ingestion_service),
) -> ProjectImportPreviewResponse:
    if not file.filename:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Filename is required for import.",
        )

    stream = await _read_upload_file(file)

    try:
        preview = ingestion_service.preview_projects(stream, file.filename)
    except UnsupportedImportFormat as exc:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(exc),
        ) from exc

    return ProjectImportPreviewResponse.model_validate(preview)


@router.post(
    "/scenarios/preview",
    response_model=ScenarioImportPreviewResponse,
    status_code=status.HTTP_200_OK,
)
async def preview_scenario_import(
    file: UploadFile = File(...,
                            description="Scenario import file (CSV or Excel)"),
    _: User = Depends(require_roles(*MANAGE_ROLES)),
    ingestion_service: ImportIngestionService = Depends(
        get_import_ingestion_service),
) -> ScenarioImportPreviewResponse:
    if not file.filename:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Filename is required for import.",
        )

    stream = await _read_upload_file(file)

    try:
        preview = ingestion_service.preview_scenarios(stream, file.filename)
    except UnsupportedImportFormat as exc:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(exc),
        ) from exc

    return ScenarioImportPreviewResponse.model_validate(preview)


def _value_error_status(exc: ValueError) -> int:
    detail = str(exc)
    if detail.lower().startswith("unknown"):
        return status.HTTP_404_NOT_FOUND
    return status.HTTP_400_BAD_REQUEST


@router.post(
    "/projects/commit",
    response_model=ProjectImportCommitResponse,
    status_code=status.HTTP_200_OK,
)
async def commit_project_import_endpoint(
    payload: ImportCommitRequest,
    _: User = Depends(require_roles(*MANAGE_ROLES)),
    ingestion_service: ImportIngestionService = Depends(
        get_import_ingestion_service),
) -> ProjectImportCommitResponse:
    try:
        result = ingestion_service.commit_project_import(payload.token)
    except ValueError as exc:
        raise HTTPException(
            status_code=_value_error_status(exc),
            detail=str(exc),
        ) from exc

    return ProjectImportCommitResponse.model_validate(result)


@router.post(
    "/scenarios/commit",
    response_model=ScenarioImportCommitResponse,
    status_code=status.HTTP_200_OK,
)
async def commit_scenario_import_endpoint(
    payload: ImportCommitRequest,
    _: User = Depends(require_roles(*MANAGE_ROLES)),
    ingestion_service: ImportIngestionService = Depends(
        get_import_ingestion_service),
) -> ScenarioImportCommitResponse:
    try:
        result = ingestion_service.commit_scenario_import(payload.token)
    except ValueError as exc:
        raise HTTPException(
            status_code=_value_error_status(exc),
            detail=str(exc),
        ) from exc

    return ScenarioImportCommitResponse.model_validate(result)
