"""Phase 6.1 supporting entity repositories."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy import select

from app.models.supporting import (
    ContactTag,
    ContactType,
    CrmAddress,
    CrmAttachment,
    CrmAuditLog,
    CrmCustomField,
    CrmCustomFieldValue,
    CrmNote,
    CrmNoteVersion,
    CrmTag,
    LeadAssignment,
    LeadSource,
    LeadStatusDefinition,
    LeadTag,
    OrganizationIndustry,
    OrganizationTag,
    OrganizationType,
)
from app.models.types import CrmEntityType
from app.repositories.base import TenantBaseRepository


class LeadSourceRepository(TenantBaseRepository[LeadSource]):
    model = LeadSource

    async def get_by_code(self, tenant_id: UUID, code: str) -> LeadSource | None:
        stmt = select(LeadSource).where(
            LeadSource.tenant_id == tenant_id, LeadSource.code == code
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class LeadStatusDefinitionRepository(TenantBaseRepository[LeadStatusDefinition]):
    model = LeadStatusDefinition

    async def get_by_code(
        self, tenant_id: UUID, code: str
    ) -> LeadStatusDefinition | None:
        stmt = select(LeadStatusDefinition).where(
            LeadStatusDefinition.tenant_id == tenant_id,
            LeadStatusDefinition.code == code,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class ContactTypeRepository(TenantBaseRepository[ContactType]):
    model = ContactType

    async def get_by_code(self, tenant_id: UUID, code: str) -> ContactType | None:
        stmt = select(ContactType).where(
            ContactType.tenant_id == tenant_id, ContactType.code == code
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class OrganizationTypeRepository(TenantBaseRepository[OrganizationType]):
    model = OrganizationType

    async def get_by_code(self, tenant_id: UUID, code: str) -> OrganizationType | None:
        stmt = select(OrganizationType).where(
            OrganizationType.tenant_id == tenant_id, OrganizationType.code == code
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class OrganizationIndustryRepository(TenantBaseRepository[OrganizationIndustry]):
    model = OrganizationIndustry

    async def get_by_code(
        self, tenant_id: UUID, code: str
    ) -> OrganizationIndustry | None:
        stmt = select(OrganizationIndustry).where(
            OrganizationIndustry.tenant_id == tenant_id,
            OrganizationIndustry.code == code,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class LeadAssignmentRepository(TenantBaseRepository[LeadAssignment]):
    model = LeadAssignment

    async def list_by_lead(self, tenant_id: UUID, lead_id: UUID):
        stmt = (
            select(LeadAssignment)
            .where(
                LeadAssignment.tenant_id == tenant_id,
                LeadAssignment.lead_id == lead_id,
            )
            .order_by(LeadAssignment.assigned_at.desc())
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def clear_current(self, tenant_id: UUID, lead_id: UUID) -> None:
        for row in await self.list_by_lead(tenant_id, lead_id):
            if row.is_current:
                row.is_current = False
        await self.session.flush()


class CrmTagRepository(TenantBaseRepository[CrmTag]):
    model = CrmTag

    async def get_by_name(self, tenant_id: UUID, name: str) -> CrmTag | None:
        stmt = select(CrmTag).where(CrmTag.tenant_id == tenant_id, CrmTag.name == name)
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class LeadTagRepository(TenantBaseRepository[LeadTag]):
    model = LeadTag

    async def list_by_lead(self, tenant_id: UUID, lead_id: UUID):
        stmt = select(LeadTag).where(
            LeadTag.tenant_id == tenant_id, LeadTag.lead_id == lead_id
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def find(self, tenant_id: UUID, lead_id: UUID, tag_id: UUID) -> LeadTag | None:
        stmt = select(LeadTag).where(
            LeadTag.tenant_id == tenant_id,
            LeadTag.lead_id == lead_id,
            LeadTag.tag_id == tag_id,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class ContactTagRepository(TenantBaseRepository[ContactTag]):
    model = ContactTag

    async def list_by_contact(self, tenant_id: UUID, contact_id: UUID):
        stmt = select(ContactTag).where(
            ContactTag.tenant_id == tenant_id, ContactTag.contact_id == contact_id
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def find(
        self, tenant_id: UUID, contact_id: UUID, tag_id: UUID
    ) -> ContactTag | None:
        stmt = select(ContactTag).where(
            ContactTag.tenant_id == tenant_id,
            ContactTag.contact_id == contact_id,
            ContactTag.tag_id == tag_id,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class OrganizationTagRepository(TenantBaseRepository[OrganizationTag]):
    model = OrganizationTag

    async def list_by_organization(self, tenant_id: UUID, organization_id: UUID):
        stmt = select(OrganizationTag).where(
            OrganizationTag.tenant_id == tenant_id,
            OrganizationTag.organization_id == organization_id,
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def find(
        self, tenant_id: UUID, organization_id: UUID, tag_id: UUID
    ) -> OrganizationTag | None:
        stmt = select(OrganizationTag).where(
            OrganizationTag.tenant_id == tenant_id,
            OrganizationTag.organization_id == organization_id,
            OrganizationTag.tag_id == tag_id,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class CrmCustomFieldRepository(TenantBaseRepository[CrmCustomField]):
    model = CrmCustomField

    async def get_by_key(
        self, tenant_id: UUID, entity_type: CrmEntityType, field_key: str
    ) -> CrmCustomField | None:
        stmt = select(CrmCustomField).where(
            CrmCustomField.tenant_id == tenant_id,
            CrmCustomField.entity_type == entity_type,
            CrmCustomField.field_key == field_key,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def list_by_entity_type(self, tenant_id: UUID, entity_type: CrmEntityType):
        stmt = (
            select(CrmCustomField)
            .where(
                CrmCustomField.tenant_id == tenant_id,
                CrmCustomField.entity_type == entity_type,
                CrmCustomField.is_active.is_(True),
            )
            .order_by(CrmCustomField.position.asc())
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class CrmCustomFieldValueRepository(TenantBaseRepository[CrmCustomFieldValue]):
    model = CrmCustomFieldValue

    async def list_for_entity(
        self, tenant_id: UUID, entity_type: CrmEntityType, entity_id: UUID
    ):
        stmt = select(CrmCustomFieldValue).where(
            CrmCustomFieldValue.tenant_id == tenant_id,
            CrmCustomFieldValue.entity_type == entity_type,
            CrmCustomFieldValue.entity_id == entity_id,
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class CrmAddressRepository(TenantBaseRepository[CrmAddress]):
    model = CrmAddress

    async def list_for_entity(
        self, tenant_id: UUID, entity_type: CrmEntityType, entity_id: UUID
    ):
        stmt = select(CrmAddress).where(
            CrmAddress.tenant_id == tenant_id,
            CrmAddress.entity_type == entity_type,
            CrmAddress.entity_id == entity_id,
            CrmAddress.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class CrmNoteRepository(TenantBaseRepository[CrmNote]):
    model = CrmNote

    async def list_for_entity(
        self, tenant_id: UUID, entity_type: CrmEntityType, entity_id: UUID
    ):
        stmt = (
            select(CrmNote)
            .where(
                CrmNote.tenant_id == tenant_id,
                CrmNote.entity_type == entity_type,
                CrmNote.entity_id == entity_id,
                CrmNote.is_deleted.is_(False),
            )
            .order_by(CrmNote.is_pinned.desc(), CrmNote.created_at.desc())
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class CrmNoteVersionRepository(TenantBaseRepository[CrmNoteVersion]):
    model = CrmNoteVersion

    async def list_for_note(self, tenant_id: UUID, note_id: UUID):
        stmt = (
            select(CrmNoteVersion)
            .where(
                CrmNoteVersion.tenant_id == tenant_id,
                CrmNoteVersion.note_id == note_id,
            )
            .order_by(CrmNoteVersion.version.desc())
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class CrmAttachmentRepository(TenantBaseRepository[CrmAttachment]):
    model = CrmAttachment

    async def list_for_entity(
        self, tenant_id: UUID, entity_type: CrmEntityType, entity_id: UUID
    ):
        stmt = select(CrmAttachment).where(
            CrmAttachment.tenant_id == tenant_id,
            CrmAttachment.entity_type == entity_type,
            CrmAttachment.entity_id == entity_id,
            CrmAttachment.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class CrmAuditLogRepository(TenantBaseRepository[CrmAuditLog]):
    model = CrmAuditLog

    async def list_for_entity(
        self, tenant_id: UUID, entity_type: str, entity_id: UUID, *, limit: int = 100
    ):
        stmt = (
            select(CrmAuditLog)
            .where(
                CrmAuditLog.tenant_id == tenant_id,
                CrmAuditLog.entity_type == entity_type,
                CrmAuditLog.entity_id == entity_id,
            )
            .order_by(CrmAuditLog.created_at.desc())
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()
