from datetime import datetime

from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.domain.entities.company import Company
from app.domain.repositories.company_repository import CompanyRepository
from app.infrastructure.db.models import CompanyModel, new_id
from app.infrastructure.repositories.mysql_utils import is_uuid


class MySQLCompanyRepository(CompanyRepository):
    def __init__(self, session: AsyncSession) -> None:
        self._session = session

    def _to_entity(self, row: CompanyModel) -> Company:
        return Company(
            id=row.id,
            company_id=row.company_id,
            name=row.name,
            address=row.address,
            logo=row.logo,
            favicon=row.favicon,
            user_id=row.user_id,
            created_at=row.created_at,
            updated_at=row.updated_at,
        )

    async def create(self, company: Company) -> Company:
        row = CompanyModel(
            id=company.id or new_id(),
            company_id=company.company_id,
            name=company.name,
            address=company.address,
            logo=company.logo,
            favicon=company.favicon,
            user_id=company.user_id,
            created_at=company.created_at,
            updated_at=company.updated_at,
        )
        self._session.add(row)
        await self._session.commit()
        await self._session.refresh(row)
        return self._to_entity(row)

    async def get_by_id(self, company_id: str) -> Company | None:
        row = await self._session.get(CompanyModel, company_id)
        return self._to_entity(row) if row else None

    async def get_by_company_id(self, company_id: str, user_id: str) -> Company | None:
        result = await self._session.execute(
            select(CompanyModel).where(
                CompanyModel.company_id == company_id,
                CompanyModel.user_id == user_id,
            )
        )
        row = result.scalar_one_or_none()
        return self._to_entity(row) if row else None

    async def get_for_user(self, company_key: str, user_id: str) -> Company | None:
        company = await self.get_by_company_id(company_key, user_id)
        if company:
            return company
        if is_uuid(company_key):
            company = await self.get_by_id(company_key)
            if company and company.user_id == user_id:
                return company
        return None

    async def list_by_user(self, user_id: str, skip: int = 0, limit: int = 100) -> list[Company]:
        result = await self._session.execute(
            select(CompanyModel)
            .where(CompanyModel.user_id == user_id)
            .order_by(CompanyModel.name.asc())
            .offset(skip)
            .limit(limit)
        )
        return [self._to_entity(row) for row in result.scalars().all()]

    async def count_by_user(self, user_id: str) -> int:
        result = await self._session.execute(
            select(func.count()).select_from(CompanyModel).where(CompanyModel.user_id == user_id)
        )
        return int(result.scalar_one())

    async def update(self, company_id: str, company: Company) -> Company | None:
        row = await self._session.get(CompanyModel, company_id)
        if not row:
            return None
        row.company_id = company.company_id
        row.name = company.name
        row.address = company.address
        row.logo = company.logo
        row.favicon = company.favicon
        row.user_id = company.user_id
        row.updated_at = datetime.utcnow()
        await self._session.commit()
        await self._session.refresh(row)
        return self._to_entity(row)

    async def delete(self, company_id: str) -> bool:
        row = await self._session.get(CompanyModel, company_id)
        if not row:
            return False
        await self._session.delete(row)
        await self._session.commit()
        return True
