"""
Competitor Benchmarking Service
===============================

Calculates category averages across all 150 NordaBiz firms and provides
comparison data for individual company audits.

Usage:
    from benchmark_service import BenchmarkService
    benchmarks = BenchmarkService(db).get_benchmarks(company_id)
"""

import logging
from typing import Dict, Optional
from sqlalchemy import func
from sqlalchemy.orm import Session

from database import (
    Company, Category, GBPAudit, CompanyWebsiteAnalysis, CompanySocialMedia
)

logger = logging.getLogger(__name__)


class BenchmarkService:
    """Calculate and compare audit scores against category averages."""

    def __init__(self, db: Session):
        self.db = db
        self._cache = {}  # Simple in-memory cache per session

    def get_category_averages(self, category_id: int) -> Dict:
        """Calculate average audit scores for a category.

        Returns:
            Dict with average scores for GBP, SEO, Social
        """
        if category_id in self._cache:
            return self._cache[category_id]

        # Get company IDs in this category
        company_ids = [c.id for c in self.db.query(Company.id).filter(
            Company.category_id == category_id
        ).all()]

        if not company_ids:
            return {}

        result = {
            'company_count': len(company_ids),
            'gbp': self._avg_gbp(company_ids),
            'seo': self._avg_seo(company_ids),
            'social': self._avg_social(company_ids),
        }

        self._cache[category_id] = result
        return result

    def _avg_gbp(self, company_ids: list) -> Dict:
        """Calculate average GBP metrics for given companies."""
        from sqlalchemy import and_

        # Get latest audit per company using subquery
        from sqlalchemy.orm import aliased

        audits = self.db.query(
            func.avg(GBPAudit.completeness_score).label('avg_score'),
            func.avg(GBPAudit.average_rating).label('avg_rating'),
            func.avg(GBPAudit.review_count).label('avg_reviews'),
            func.avg(GBPAudit.photo_count).label('avg_photos'),
            func.count(GBPAudit.id).label('total'),
        ).filter(
            GBPAudit.company_id.in_(company_ids)
        ).first()

        if not audits or not audits.total:
            return {}

        return {
            'avg_completeness_score': round(float(audits.avg_score or 0), 1),
            'avg_rating': round(float(audits.avg_rating or 0), 2),
            'avg_review_count': round(float(audits.avg_reviews or 0), 1),
            'avg_photo_count': round(float(audits.avg_photos or 0), 1),
            'audited_count': audits.total,
        }

    def _avg_seo(self, company_ids: list) -> Dict:
        """Calculate average SEO metrics for given companies."""
        analyses = self.db.query(
            func.avg(CompanyWebsiteAnalysis.pagespeed_seo_score).label('avg_seo'),
            func.avg(CompanyWebsiteAnalysis.pagespeed_performance_score).label('avg_perf'),
            func.avg(CompanyWebsiteAnalysis.pagespeed_accessibility_score).label('avg_acc'),
            func.avg(CompanyWebsiteAnalysis.load_time_ms).label('avg_load'),
            func.count(CompanyWebsiteAnalysis.id).label('total'),
        ).filter(
            CompanyWebsiteAnalysis.company_id.in_(company_ids),
            CompanyWebsiteAnalysis.pagespeed_seo_score.isnot(None),
        ).first()

        if not analyses or not analyses.total:
            return {}

        return {
            'avg_seo_score': round(float(analyses.avg_seo or 0), 1),
            'avg_performance_score': round(float(analyses.avg_perf or 0), 1),
            'avg_accessibility_score': round(float(analyses.avg_acc or 0), 1),
            'avg_load_time_ms': round(float(analyses.avg_load or 0)),
            'audited_count': analyses.total,
        }

    def _avg_social(self, company_ids: list) -> Dict:
        """Calculate average social media metrics for given companies."""
        # Count platforms per company and average followers
        profiles = self.db.query(
            func.count(func.distinct(CompanySocialMedia.company_id)).label('companies_with_social'),
            func.avg(CompanySocialMedia.followers_count).label('avg_followers'),
            func.avg(CompanySocialMedia.profile_completeness_score).label('avg_completeness'),
        ).filter(
            CompanySocialMedia.company_id.in_(company_ids),
            CompanySocialMedia.is_valid == True,
        ).first()

        # Average platform count per company
        platform_counts = self.db.query(
            CompanySocialMedia.company_id,
            func.count(CompanySocialMedia.id).label('platforms'),
        ).filter(
            CompanySocialMedia.company_id.in_(company_ids),
            CompanySocialMedia.is_valid == True,
        ).group_by(CompanySocialMedia.company_id).all()

        avg_platforms = 0
        if platform_counts:
            avg_platforms = round(sum(p.platforms for p in platform_counts) / len(platform_counts), 1)

        if not profiles or not profiles.companies_with_social:
            return {}

        return {
            'avg_followers': round(float(profiles.avg_followers or 0)),
            'avg_completeness': round(float(profiles.avg_completeness or 0), 1),
            'avg_platform_count': avg_platforms,
            'companies_with_social': profiles.companies_with_social,
        }

    def get_benchmarks(self, company_id: int) -> Optional[Dict]:
        """Get benchmark comparison for a specific company.

        Returns:
            Dict with category averages and company's position relative to them.
        """
        company = self.db.query(Company).filter(Company.id == company_id).first()
        if not company or not company.category_id:
            return None

        category = self.db.query(Category).filter(Category.id == company.category_id).first()
        averages = self.get_category_averages(company.category_id)

        if not averages:
            return None

        return {
            'category_name': category.name if category else 'Unknown',
            'category_company_count': averages.get('company_count', 0),
            'gbp': averages.get('gbp', {}),
            'seo': averages.get('seo', {}),
            'social': averages.get('social', {}),
        }
