# app/modules/tenancy/services/platform_service.py
"""
Platform Service

Business logic for platform management in the Multi-Platform CMS.

Platforms represent different business offerings (OMS, Loyalty, Site Builder, Main Marketing).
Each platform has its own:
- Marketing pages (homepage, pricing, features)
- Vendor defaults (about, terms, privacy)
- Configuration and branding
"""

import logging
from dataclasses import dataclass

from sqlalchemy import func
from sqlalchemy.orm import Session

from app.modules.tenancy.exceptions import (
    PlatformNotFoundException,
)
from app.modules.cms.models import ContentPage
from app.modules.tenancy.models import Platform
from app.modules.tenancy.models import VendorPlatform

logger = logging.getLogger(__name__)


@dataclass
class PlatformStats:
    """Platform statistics."""

    platform_id: int
    platform_code: str
    platform_name: str
    vendor_count: int
    platform_pages_count: int
    vendor_defaults_count: int
    vendor_overrides_count: int = 0
    published_pages_count: int = 0
    draft_pages_count: int = 0


class PlatformService:
    """Service for platform operations."""

    @staticmethod
    def get_platform_by_code(db: Session, code: str) -> Platform:
        """
        Get platform by code.

        Args:
            db: Database session
            code: Platform code (oms, loyalty, main, etc.)

        Returns:
            Platform object

        Raises:
            PlatformNotFoundException: If platform not found
        """
        platform = db.query(Platform).filter(Platform.code == code).first()

        if not platform:
            raise PlatformNotFoundException(code)

        return platform

    @staticmethod
    def get_platform_by_code_optional(db: Session, code: str) -> Platform | None:
        """
        Get platform by code, returns None if not found.

        Args:
            db: Database session
            code: Platform code

        Returns:
            Platform object or None
        """
        return db.query(Platform).filter(Platform.code == code).first()

    @staticmethod
    def get_platform_by_id(db: Session, platform_id: int) -> Platform:
        """
        Get platform by ID.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Platform object

        Raises:
            PlatformNotFoundException: If platform not found
        """
        platform = db.query(Platform).filter(Platform.id == platform_id).first()

        if not platform:
            raise PlatformNotFoundException(str(platform_id))

        return platform

    @staticmethod
    def list_platforms(
        db: Session, include_inactive: bool = False
    ) -> list[Platform]:
        """
        List all platforms.

        Args:
            db: Database session
            include_inactive: Include inactive platforms

        Returns:
            List of Platform objects
        """
        query = db.query(Platform)

        if not include_inactive:
            query = query.filter(Platform.is_active == True)

        return query.order_by(Platform.id).all()

    @staticmethod
    def get_vendor_count(db: Session, platform_id: int) -> int:
        """
        Get count of vendors on a platform.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Vendor count
        """
        return (
            db.query(func.count(VendorPlatform.vendor_id))
            .filter(VendorPlatform.platform_id == platform_id)
            .scalar()
            or 0
        )

    @staticmethod
    def get_platform_pages_count(db: Session, platform_id: int) -> int:
        """
        Get count of platform marketing pages.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Platform pages count
        """
        return (
            db.query(func.count(ContentPage.id))
            .filter(
                ContentPage.platform_id == platform_id,
                ContentPage.vendor_id == None,
                ContentPage.is_platform_page == True,
            )
            .scalar()
            or 0
        )

    @staticmethod
    def get_vendor_defaults_count(db: Session, platform_id: int) -> int:
        """
        Get count of vendor default pages.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Vendor defaults count
        """
        return (
            db.query(func.count(ContentPage.id))
            .filter(
                ContentPage.platform_id == platform_id,
                ContentPage.vendor_id == None,
                ContentPage.is_platform_page == False,
            )
            .scalar()
            or 0
        )

    @staticmethod
    def get_vendor_overrides_count(db: Session, platform_id: int) -> int:
        """
        Get count of vendor override pages.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Vendor overrides count
        """
        return (
            db.query(func.count(ContentPage.id))
            .filter(
                ContentPage.platform_id == platform_id,
                ContentPage.vendor_id != None,
            )
            .scalar()
            or 0
        )

    @staticmethod
    def get_published_pages_count(db: Session, platform_id: int) -> int:
        """
        Get count of published pages on a platform.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Published pages count
        """
        return (
            db.query(func.count(ContentPage.id))
            .filter(
                ContentPage.platform_id == platform_id,
                ContentPage.is_published == True,
            )
            .scalar()
            or 0
        )

    @staticmethod
    def get_draft_pages_count(db: Session, platform_id: int) -> int:
        """
        Get count of draft pages on a platform.

        Args:
            db: Database session
            platform_id: Platform ID

        Returns:
            Draft pages count
        """
        return (
            db.query(func.count(ContentPage.id))
            .filter(
                ContentPage.platform_id == platform_id,
                ContentPage.is_published == False,
            )
            .scalar()
            or 0
        )

    @classmethod
    def get_platform_stats(cls, db: Session, platform: Platform) -> PlatformStats:
        """
        Get comprehensive statistics for a platform.

        Args:
            db: Database session
            platform: Platform object

        Returns:
            PlatformStats dataclass
        """
        return PlatformStats(
            platform_id=platform.id,
            platform_code=platform.code,
            platform_name=platform.name,
            vendor_count=cls.get_vendor_count(db, platform.id),
            platform_pages_count=cls.get_platform_pages_count(db, platform.id),
            vendor_defaults_count=cls.get_vendor_defaults_count(db, platform.id),
            vendor_overrides_count=cls.get_vendor_overrides_count(db, platform.id),
            published_pages_count=cls.get_published_pages_count(db, platform.id),
            draft_pages_count=cls.get_draft_pages_count(db, platform.id),
        )

    @staticmethod
    def update_platform(
        db: Session, platform: Platform, update_data: dict
    ) -> Platform:
        """
        Update platform fields.

        Note: This method does NOT commit the transaction.
        The caller (API endpoint) is responsible for committing.

        Args:
            db: Database session
            platform: Platform to update
            update_data: Dictionary of fields to update

        Returns:
            Updated Platform object (with pending changes)
        """
        for field, value in update_data.items():
            if hasattr(platform, field):
                setattr(platform, field, value)

        logger.info(f"[PLATFORMS] Updated platform: {platform.code}")

        return platform


# Singleton instance for convenience
platform_service = PlatformService()
