import datetime

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession

from src.services.project_service import ProjectService
from src.services.form3_phase_service import Form3PhaseService
from src.services.rf_project_report_service import RfProjectReportService
from src.services.org_unit_service import OrgUnitService
from src.db.models.app_user import AppUser
from src.domain.schemas import (
    BaseListResponse,
    BaseSingleResponse,
    Form3PhaseCreate,
    Form3PhaseResponse,
    Form3PhaseUpdate,
    FormPhaseCreate,
    FormPhaseResponse,
    FormPhaseUpdate,
)
from src.services.budget_form_service import BudgetFormService
from src.services.form_phase_service import FormPhaseService
from src.api.v1.deps import (
    get_current_active_user_with_set_db,
    require_admin,
)
from src.db.session import get_db

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


def timezone_from_offset(offset: str) -> datetime.timezone | None:
    if not offset:
        return None
    
    hours = int(offset[1:])
    return datetime.timezone(
        datetime.timedelta(
            hours=hours if offset[0] == '+' else -hours
        )
    )


@router.get("/form/{form_id}")
async def get_form_phases(
    form_id: int,
    sheet: str | None = None,
    phase_code: str | None = None,
    db: AsyncSession = Depends(get_db),
    current_user: AppUser = Depends(get_current_active_user_with_set_db),
) -> BaseListResponse[FormPhaseResponse]:
    fp_service = FormPhaseService(db)
    org_unit_service = OrgUnitService(db)
    bf_service = BudgetFormService(db)

    phases = await fp_service.get_list(
        budget_form_id=form_id,
        user=current_user,
        sheet=sheet,
        phase_code=phase_code,
    )
    if phases:
        form = await bf_service.get(user=current_user, budget_form_id=form_id)
        org_unit = await org_unit_service.get(user=current_user, org_unit_id=form.org_unit_id)
        result = [FormPhaseResponse.model_validate(p) for p in phases]
        if org_unit.utc_offset:
            tz = timezone_from_offset(org_unit.utc_offset)
            for element in result:
                if element.opens_at:
                    element.opens_at = element.opens_at.astimezone(tz)
                if element.closes_at:
                    element.closes_at = element.closes_at.astimezone(tz)
    else:
        result = []
    return BaseListResponse(
        result=result,
        count=len(phases),
    )


@router.post("/form/{form_id}")
async def create_form_phase(
        form_id: int,
        body: FormPhaseCreate,
        db: AsyncSession = Depends(get_db),
        current_user: AppUser = Depends(require_admin),
) -> BaseSingleResponse[FormPhaseResponse]:
    bf_service = BudgetFormService(db)
    form = await bf_service.get(budget_form_id=form_id, user=current_user, load_form_type=True)
    if not form:
        raise HTTPException(404, "Форма не найдена")
    
    org_unit_service = OrgUnitService(db)
    org_unit = await org_unit_service.get(user=current_user, org_unit_id=form.org_unit_id)

    fp_service = FormPhaseService(db)
    phase = await fp_service.create(
        budget_form=form, 
        body=body, 
        user=current_user,
    )

    result = FormPhaseResponse.model_validate(phase)

    if org_unit.utc_offset:
        tz = timezone_from_offset(org_unit.utc_offset)
        if result.opens_at:
            result.opens_at = result.opens_at.astimezone(tz)
        if result.closes_at:
            result.closes_at = result.closes_at.astimezone(tz)
    return BaseSingleResponse(result=result)


@router.patch("/form/{form_id}/{sheet}/{phase_code}")
async def update_form_phase(
    form_id: int,
    sheet: str,
    phase_code: str,
    body: FormPhaseUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: AppUser = Depends(require_admin),
) -> BaseSingleResponse[FormPhaseResponse]:
    bf_service = BudgetFormService(db)
    form = await bf_service.get(budget_form_id=form_id, user=current_user, load_form_type=True)
    if not form:
        raise HTTPException(404, "Форма не найдена")
    
    fp_service = FormPhaseService(db)
    phase = await fp_service.update(
        budget_form=form,
        sheet=sheet,
        phase_code=phase_code,
        body=body,
        user=current_user,
    )
    
    if not phase:
        raise HTTPException(404, "Этап не найден")

    org_unit_service = OrgUnitService(db)
    org_unit = await org_unit_service.get(user=current_user, org_unit_id=form.org_unit_id)
    result = FormPhaseResponse.model_validate(phase)

    if org_unit.utc_offset:
        tz = timezone_from_offset(org_unit.utc_offset)
        if result.opens_at:
            result.opens_at = result.opens_at.astimezone(tz)
        if result.closes_at:
            result.closes_at = result.closes_at.astimezone(tz)
    return BaseSingleResponse(result=result)


@router.delete("/form/{form_id}/{sheet}/{phase_code}")
async def delete_form_phase(
    form_id: int,
    sheet: str,
    phase_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: AppUser = Depends(require_admin),
):
    bf_service = BudgetFormService(db)
    form = await bf_service.get(budget_form_id=form_id, user=current_user)
    if not form:
        raise HTTPException(404, "Форма не найдена")
    
    fp_service = FormPhaseService(db)
    deleted = await fp_service.delete(
        budget_form_id=form_id,
        sheet=sheet,
        phase_code=phase_code,
        user=current_user,
    )
    if not deleted:
        raise HTTPException(404, "Этап не найден")


@router.get("/project/{project_id}")
async def get_form3_phases(
    project_id: int,
    year: int | None = None,
    report_type: str | None = None,
    phase_code: str | None = None,
    db: AsyncSession = Depends(get_db),
    current_user: AppUser = Depends(get_current_active_user_with_set_db),
) -> BaseListResponse[Form3PhaseResponse]:
    f3p_service = Form3PhaseService(db)
    report_service = RfProjectReportService(db)
    project_service = ProjectService(db)
    org_unit_service = OrgUnitService(db)

    reports = await report_service.get_list(
        project_id=project_id,
        year=year,
        report_type=report_type,
    )

    phases = await f3p_service.get_list(
        report_id=[el.id for el in reports],
        phase_code=phase_code,
    )
    if phases:
        project = await project_service.get_instance(user=current_user, project_id=project_id)
        org_unit = await org_unit_service.get(user=current_user, org_unit_id=project.org_unit_id)
        result = [Form3PhaseResponse.model_validate(p) for p in phases]
        if org_unit.utc_offset:
            tz = timezone_from_offset(org_unit.utc_offset)
            for element in result:
                if element.opens_at:
                    element.opens_at = element.opens_at.astimezone(tz)
                if element.closes_at:
                    element.closes_at = element.closes_at.astimezone(tz)
    else:
        result = []
    if result:
        reports = {report.id: report for report in reports}
        for i, element in enumerate(result):
            element.year = reports[phases[i].rf_project_report_id].year
            element.report_type = reports[phases[i].rf_project_report_id].report_type
    return BaseListResponse(
        result=result,
        count=len(phases),
    )


@router.post("/project/{project_id}")
async def create_form3_phase(
        project_id: int,
        body: Form3PhaseCreate,
        db: AsyncSession = Depends(get_db),
        current_user: AppUser = Depends(require_admin),
) -> BaseSingleResponse[Form3PhaseResponse]:
    report_service = RfProjectReportService(db)
    report = await report_service.get(
        project_id=project_id, 
        report_type=body.report_type,
        year=body.year,
        user=current_user, 
        load_project=True,
    )
    if not report:
        raise HTTPException(404, "Форма не найдена")
    
    org_unit_service = OrgUnitService(db)
    org_unit = await org_unit_service.get(user=current_user, org_unit_id=report.project.org_unit_id)

    f3p_service = Form3PhaseService(db)
    phase = await f3p_service.create(
        report_id=report.id, 
        body=body, 
        user=current_user,
    )

    result = Form3PhaseResponse.model_validate(phase)

    if org_unit.utc_offset:
        tz = timezone_from_offset(org_unit.utc_offset)
        if result.opens_at:
            result.opens_at = result.opens_at.astimezone(tz)
        if result.closes_at:
            result.closes_at = result.closes_at.astimezone(tz)
    
    result.year = body.year
    result.report_type = body.report_type

    return BaseSingleResponse(result=result)


@router.patch("/project/{project_id}/{year}/{report_type}/{phase_code}")
async def update_form3_phase(
    project_id: int,
    year: int,
    report_type: str,
    phase_code: str,
    body: Form3PhaseUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: AppUser = Depends(require_admin),
) -> BaseSingleResponse[Form3PhaseResponse]:
    report_service = RfProjectReportService(db)
    report = await report_service.get(
        project_id=project_id, 
        report_type=report_type,
        year=year,
        user=current_user, 
        load_project=True,
    )
    if not report:
        raise HTTPException(404, "Форма не найдена")
    
    f3p_service = Form3PhaseService(db)
    phase = await f3p_service.update(
        report_id=report.id,
        phase_code=phase_code,
        body=body,
        user=current_user,
    )
    
    if not phase:
        raise HTTPException(404, "Этап не найден")

    org_unit_service = OrgUnitService(db)
    org_unit = await org_unit_service.get(user=current_user, org_unit_id=report.project.org_unit_id)
    result = Form3PhaseResponse.model_validate(phase)

    if org_unit.utc_offset:
        tz = timezone_from_offset(org_unit.utc_offset)
        if result.opens_at:
            result.opens_at = result.opens_at.astimezone(tz)
        if result.closes_at:
            result.closes_at = result.closes_at.astimezone(tz)
    
    result.year = year
    result.report_type = report_type

    return BaseSingleResponse(result=result)


@router.delete("/project/{project_id}/{year}/{report_type}/{phase_code}")
async def delete_form3_phase(
    project_id: int,
    year: int,
    report_type: str,
    phase_code: str,
    db: AsyncSession = Depends(get_db),
    current_user: AppUser = Depends(require_admin),
):
    report_service = RfProjectReportService(db)
    report = await report_service.get(
        project_id=project_id, 
        report_type=report_type,
        year=year,
        user=current_user, 
        load_project=True,
    )
    if not report:
        raise HTTPException(404, "Форма не найдена")
    
    f3p_service = Form3PhaseService(db)
    deleted = await f3p_service.delete(
        report_id=report.id,
        phase_code=phase_code,
        user=current_user,
    )
    if not deleted:
        raise HTTPException(404, "Этап не найден")
