
from sqlalchemy.ext.asyncio import AsyncSession

from src.db.models.form4_project import Form4ProjectLevelEnum
from src.db.models.role import UserRoleEnum
from src.repository.budget_form_repository import BudgetFormRepository
from src.repository.form4_project_repository import Form4ProjectRepository
from src.repository.user_repository import UserRepository
from src.db.models.app_user import AppUser
from src.db.models.budget_form import BudgetForm
from src.repository.sheet_repository import SheetRepository, SheetValidationError



class SheetService:
    def __init__(self, db: AsyncSession):
        self.db = db
        self.sheet_repo = SheetRepository(db)
        self.bf_repo = BudgetFormRepository(db)
        self.user_repo = UserRepository(db)
        self.f4_project_repo = Form4ProjectRepository(db)

    async def get(
            self, 
            sheet: str, 
            direction: str | None, 
            sections: list[str] | None = None,
            form_id: int | None = None,
            form: BudgetForm | None = None
    ) -> list[tuple]:        
        return await self.sheet_repo.get(
            form_id=form_id,
            sheet=sheet,
            direction=direction,
            sections=sections,
        )

    async def update_cells(
            self, 
            form_id: int, 
            sheet: str,
            direction: str | None,
            sections: list[str] | None,
            changes: list[dict],
            user: AppUser | None = None,
    ) -> list[tuple]:
        return await self.sheet_repo.update_cells(
            form_id=form_id, 
            sheet=sheet,
            direction=direction,
            sections=sections,
            changes=changes,
            user_id=user.id if user else None,
        )
    
    async def update_cell(
            self, 
            form_id: int, 
            sheet: str,
            direction: str | None,
            sections: list[str] | None,
            line_id: int, 
            column: str, 
            value: str | int | float | None = None, 
            user: AppUser | None = None,
    ) -> list[tuple]:
        return await self.sheet_repo.update_cell(
            form_id=form_id, 
            sheet=sheet,
            direction=direction,
            sections=sections,
            line_id=line_id, 
            column=column, 
            value=value, 
            user_id=user.id if user else None,
        )


    async def add_line(
            self, 
            form_id: int,
            sheet: str,
            expense_item_id: int | None = None,
            item_id: str | None = None,
            section_code: str | None = None,
            direction: str | None = None,
            name: str | None = None,
            internal_order: str | None = None,
            vsp_id: int | None = None,
            project_id: int | None = None,
            justification: str | None = None,
            contract_number: str | None = None,
            contract_end_date: str | None = None,
            user: AppUser | None = None,
    ) -> list[tuple]:
        return await self.sheet_repo.add_line(
            form_id=form_id,
            sheet=sheet,
            expense_item_id=expense_item_id,
            item_id=item_id,
            section_code=section_code,
            direction=direction,
            name=name,
            internal_order=internal_order,
            vsp_id=vsp_id,
            project_id=project_id,
            justification=justification,
            contract_number=contract_number,
            contract_end_date=contract_end_date,
            user_id=user.id if user else None,
        )
    
    async def add_program(
            self, 
            form_id: int,
            sheet: str,
            name: str,
            user: AppUser | None = None,
    ) -> tuple[int, list[tuple]]:
        if user.role_id != UserRoleEnum.ADMIN:
            user = await self.user_repo.get(
                user_id=user.id,
                load_orgs=True,
            )
            form = await self.bf_repo.get(
                budget_form_id=form_id,
                org_unit=[ou.id for ou in user.org_units],
            )
            if not form:
                raise SheetValidationError("Форма не найдена")

        result = await self.sheet_repo.add_program(
            form_id=form_id,
            sheet=sheet,
            name=name,
        )
        if result:
            return (result[0][0], [tuple(r[1:]) for r in result])
        return None
    
    async def add_project(
            self, 
            name: str,
            program_id: int,
            user: AppUser | None = None,
    ) -> tuple[int, list[tuple]]:
        if user.role_id != UserRoleEnum.ADMIN:
            program = await self.f4_project_repo.get(
                project_id=program_id,
                level=Form4ProjectLevelEnum.PROGRAM,
            )
            if not program:
                raise SheetValidationError("Программа не найдена")

            user = await self.user_repo.get(
                user_id=user.id,
                load_orgs=True,
            )
            form = await self.bf_repo.get(
                budget_form_id=program.form_id,
                org_unit=[ou.id for ou in user.org_units],
            )
            if not form:
                raise SheetValidationError("Программа не найдена")
        result = await self.sheet_repo.add_project(
            program_id=program_id,
            name=name,
        )
        if result:
            return (result[0][0], [tuple(r[1:]) for r in result])
        return None

    async def delete_line(
            self,
            form_id: int,
            sheet: str,
            row_id: int,
            direction: str | None = None,
            user: AppUser | None = None,
    ) -> list[tuple]:
        return await self.sheet_repo.delete_line(
            sheet=sheet,
            row_id=row_id,
            direction=direction,
        )