"""CRM foundation application services — quotes + collaboration activity re-exports."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy.ext.asyncio import AsyncSession

from app.events.publisher import InMemoryEventPublisher, get_event_publisher
from app.events.types import CrmEventType
from app.models.foundation import Quote
from app.repositories.foundation import QuoteRepository
from app.schemas.foundation import QuoteCreate, QuoteUpdate
from app.services.collaboration_services import SalesActivityService
from app.services.contact_service import ContactService
from app.services.lead_service import LeadService
from app.services.opportunity_service import OpportunityService, PipelineService
from app.services.organization_service import OrganizationService
from app.validators import (
    ensure_quote_mutable,
    ensure_quote_number,
    validate_amount,
    validate_currency_code,
    validate_non_empty,
)
from shared.exceptions import AppError, NotFoundError

__all__ = [
    "LeadService",
    "ContactService",
    "OrganizationService",
    "PipelineService",
    "OpportunityService",
    "SalesActivityService",
    "QuoteService",
]


def _apply_update(entity, data: dict) -> None:
    for key, value in data.items():
        setattr(entity, key, value)


class QuoteService:
    def __init__(
        self,
        session: AsyncSession,
        publisher: InMemoryEventPublisher | None = None,
    ) -> None:
        self.session = session
        self.repo = QuoteRepository(session)
        self.publisher = publisher or get_event_publisher()

    async def create(self, tenant_id: UUID, body: QuoteCreate) -> Quote:
        title = validate_non_empty(body.title, field="title")
        quote_number = ensure_quote_number(body.quote_number)
        amount = validate_amount(body.amount)
        currency = validate_currency_code(body.currency_code)
        if await self.repo.get_by_number(tenant_id, quote_number) is not None:
            raise AppError(
                "شماره پیش‌فاکتور تکراری است",
                status_code=409,
                error_code="quote_number_exists",
            )
        entity = Quote(
            tenant_id=tenant_id,
            **{
                **body.model_dump(),
                "title": title,
                "quote_number": quote_number,
                "amount": amount,
                "currency_code": currency,
            },
        )
        await self.repo.add(entity)
        await self.session.commit()
        await self.session.refresh(entity)
        self.publisher.publish(
            event_type=CrmEventType.QUOTE_CREATED,
            aggregate_type="quote",
            aggregate_id=entity.id,
            tenant_id=tenant_id,
            payload={"quote_number": entity.quote_number, "amount": str(entity.amount)},
        )
        return entity

    async def update(self, tenant_id: UUID, quote_id: UUID, body: QuoteUpdate) -> Quote:
        entity = await self.repo.get(tenant_id, quote_id)
        if entity is None:
            raise NotFoundError("پیش‌فاکتور یافت نشد", error_code="quote_not_found")
        ensure_quote_mutable(entity.status)
        data = body.model_dump(exclude_unset=True)
        if "title" in data:
            data["title"] = validate_non_empty(data["title"], field="title")
        if "amount" in data and data["amount"] is not None:
            data["amount"] = validate_amount(data["amount"])
        if "currency_code" in data and data["currency_code"] is not None:
            data["currency_code"] = validate_currency_code(data["currency_code"])
        _apply_update(entity, data)
        await self.session.commit()
        await self.session.refresh(entity)
        self.publisher.publish(
            event_type=CrmEventType.QUOTE_UPDATED,
            aggregate_type="quote",
            aggregate_id=entity.id,
            tenant_id=tenant_id,
            payload={"status": entity.status.value},
        )
        return entity

    async def get(self, tenant_id: UUID, quote_id: UUID) -> Quote:
        entity = await self.repo.get(tenant_id, quote_id)
        if entity is None:
            raise NotFoundError("پیش‌فاکتور یافت نشد", error_code="quote_not_found")
        return entity

    async def list(self, tenant_id: UUID, *, offset: int, limit: int):
        return await self.repo.list_by_tenant(tenant_id, offset=offset, limit=limit)
