"""
Сервис генерации еженедельного дайджеста
"""
import logging
import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, desc
from database.models import (
    User, Message, Poll, Ad, Event, Schedule, VerificationRequest
)

logger = logging.getLogger(__name__)


class DigestService:
    """Сервис для генерации и управления дайджестами"""

    def __init__(self, session: AsyncSession):
        self.session = session

    async def generate_weekly_digest(self, year: int = None, week: int = None) -> Optional[Dict]:
        """
        Сгенерировать дайджест за неделю
        Возвращает dict с данными для формирования текста
        """
        from datetime import date

        # Если не указаны год/неделя - берём текущую
        if year is None or week is None:
            today = date.today()
            year, week, _ = today.isocalendar()

        # Определяем период (понедельник - воскресенье)
        monday = date.fromisocalendar(year, week, 1)
        sunday = date.fromisocalendar(year, week, 7)

        period_start = datetime.combine(monday, datetime.min.time())
        period_end = datetime.combine(sunday, datetime.max.time())

        logger.info(f"📰 Генерация дайджеста: {period_start} - {period_end}")

        # Собираем данные
        events = await self._get_events(period_start, period_end)
        polls = await self._get_polls(period_start, period_end)
        ads = await self._get_ads(period_start, period_end)
        top_users = await self._get_top_users(period_start, period_end)
        schedule = await self._get_schedule(period_end, period_end + timedelta(days=7))
        verifications = await self._get_verifications(period_start, period_end)
        stats = await self._get_stats(period_start, period_end)

        content = {
            'period_start': period_start.isoformat(),
            'period_end': period_end.isoformat(),
            'week_number': week,
            'year': year,
            'events': events,
            'polls': polls,
            'ads': ads,
            'top_users': top_users,
            'schedule': schedule,
            'verifications': verifications,
            'stats': stats,
        }

        # Формируем текст
        digest_text = self._format_digest_text(content)

        return {
            'content': content,
            'text': digest_text,
            'period_start': period_start,
            'period_end': period_end,
            'week_number': week,
            'year': year,
        }

    async def _get_events(self, start: datetime, end: datetime) -> List[Dict]:
        """Получить события за период"""
        stmt = (
            select(Event)
            .where(Event.event_date >= start)
            .where(Event.event_date <= end)
            .where(Event.is_active == True)
            .order_by(Event.event_date)
        )
        result = await self.session.execute(stmt)
        events = list(result.scalars().all())

        return [
            {
                'id': e.id,
                'title': e.title,
                'event_date': e.event_date.strftime('%d.%m.%Y %H:%M'),
                'location': e.location or 'Не указано',
                'type': e.event_type,
            }
            for e in events
        ]

    async def _get_polls(self, start: datetime, end: datetime) -> List[Dict]:
        """Получить опросы за период"""
        stmt = (
            select(Poll)
            .where(Poll.created_at >= start)
            .where(Poll.created_at <= end)
            .order_by(Poll.created_at.desc())
        )
        result = await self.session.execute(stmt)
        polls = list(result.scalars().all())

        return [
            {
                'id': p.poll_id,
                'question': p.question[:100],
                'total_votes': p.total_votes,
                'is_active': p.is_active,
            }
            for p in polls
        ]

    async def _get_ads(self, start: datetime, end: datetime) -> Dict:
        """Получить статистику объявлений"""
        new_stmt = (
            select(func.count(Ad.ad_id))
            .where(Ad.created_at >= start)
            .where(Ad.created_at <= end)
        )
        new_count = (await self.session.execute(new_stmt)).scalar() or 0

        active_stmt = select(func.count(Ad.ad_id)).where(Ad.is_active == True)
        active_count = (await self.session.execute(active_stmt)).scalar() or 0

        return {
            'new_count': new_count,
            'active_count': active_count,
        }

    async def _get_top_users(self, start: datetime, end: datetime) -> List[Dict]:
        """Получить топ-5 активных жильцов"""
        # Считаем сообщения за период
        stmt = (
            select(
                User.user_id,
                User.first_name,
                User.last_name,
                User.username,
                User.apartment,
                func.count(Message.id).label('msg_count')
            )
            .join(Message, User.user_id == Message.user_id)
            .where(Message.timestamp >= start)
            .where(Message.timestamp <= end)
            .where(User.verified == True)
            .group_by(User.user_id)
            .order_by(desc('msg_count'))
            .limit(5)
        )
        result = await self.session.execute(stmt)
        rows = result.all()

        return [
            {
                'user_id': r.user_id,
                'name': r.first_name or r.username or f'User{r.user_id}',
                'apartment': r.apartment or '-',
                'messages': r.msg_count,
            }
            for r in rows
        ]

    async def _get_schedule(self, start: datetime, end: datetime) -> List[Dict]:
        """Получить отключения на следующую неделю"""
        stmt = (
            select(Schedule)
            .where(Schedule.start_time >= start)
            .where(Schedule.start_time <= end)
            .where(Schedule.is_active == True)
            .order_by(Schedule.start_time)
        )
        result = await self.session.execute(stmt)
        schedules = list(result.scalars().all())

        return [
            {
                'id': s.schedule_id,
                'title': s.title,
                'type': s.schedule_type,
                'start_time': s.start_time.strftime('%d.%m %H:%M'),
                'end_time': s.end_time.strftime('%d.%m %H:%M'),
                'emoji': s.get_type_emoji(),
            }
            for s in schedules
        ]

    async def _get_verifications(self, start: datetime, end: datetime) -> Dict:
        """Получить статистику верификаций"""
        new_stmt = (
            select(func.count(VerificationRequest.id))
            .where(VerificationRequest.created_at >= start)
            .where(VerificationRequest.created_at <= end)
            .where(VerificationRequest.status == 'approved')
        )
        new_count = (await self.session.execute(new_stmt)).scalar() or 0

        total_stmt = select(func.count(User.user_id)).where(User.verified == True)
        total_count = (await self.session.execute(total_stmt)).scalar() or 0

        return {
            'new_verified': new_count,
            'total_verified': total_count,
        }

    async def _get_stats(self, start: datetime, end: datetime) -> Dict:
        """Получить общую статистику"""
        # Сообщения
        msg_stmt = (
            select(func.count(Message.id))
            .where(Message.timestamp >= start)
            .where(Message.timestamp <= end)
        )
        msg_count = (await self.session.execute(msg_stmt)).scalar() or 0

        # Активные пользователи (кто писал сообщения)
        active_stmt = (
            select(func.count(func.distinct(Message.user_id)))
            .where(Message.timestamp >= start)
            .where(Message.timestamp <= end)
        )
        active_users = (await self.session.execute(active_stmt)).scalar() or 0

        return {
            'messages_count': msg_count,
            'active_users': active_users,
        }

    def _format_digest_text(self, content: Dict) -> str:
        """Сформировать текст дайджеста"""
        events = content['events']
        polls = content['polls']
        ads = content['ads']
        top_users = content['top_users']
        schedule = content['schedule']
        verifications = content['verifications']
        stats = content['stats']

        period_start = datetime.fromisoformat(content['period_start']).strftime('%d.%m')
        period_end = datetime.fromisoformat(content['period_end']).strftime('%d.%m.%Y')

        text = f"📰 <b>ДАЙДЖЕСТ ДОМА ЗА НЕДЕЛЮ</b>\n"
        text += f"🗓 {period_start} - {period_end}\n\n"

        # События
        text += f"🔔 <b>События:</b>\n"
        if events:
            for e in events:
                text += f"• {e['title']} — {e['event_date']}\n"
        else:
            text += "• Нет событий\n"
        text += "\n"

        # Опросы
        text += f"📊 <b>Опросы:</b>\n"
        if polls:
            for p in polls:
                status = "✅ активен" if p['is_active'] else "🔴 завершён"
                text += f"• \"{p['question']}\" — {p['total_votes']} голосов ({status})\n"
        else:
            text += "• Нет опросов\n"
        text += "\n"

        # Объявления
        text += f"📢 <b>Объявления:</b> {ads['new_count']} новых\n"
        text += f"   Всего активных: {ads['active_count']}\n\n"

        # Топ жильцов
        if top_users:
            text += f"🏆 <b>Активные жильцы:</b>\n"
            for i, u in enumerate(top_users, 1):
                medal = ['🥇', '🥈', '🥉'][i-1] if i <= 3 else '  '
                text += f"{medal} {u['name']} (кв. {u['apartment']}) — {u['messages']} сообщ.\n"
            text += "\n"

        # Отключения
        if schedule:
            text += f"⏰ <b>На следующей неделе:</b>\n"
            for s in schedule:
                text += f"{s['emoji']} {s['title']} — {s['start_time']} до {s['end_time']}\n"
            text += "\n"

        # Верификации
        text += f"✅ <b>Верификации:</b>\n"
        text += f"• Новых за неделю: {verifications['new_verified']}\n"
        text += f"• Всего верифицировано: {verifications['total_verified']}\n\n"

        # Статистика
        text += f"📈 <b>Статистика:</b>\n"
        text += f"• Сообщений в чате: {stats['messages_count']}\n"
        text += f"• Активных жильцов: {stats['active_users']}\n"

        return text

    async def save_digest(self, digest_data: Dict, status: str = 'draft') -> int:
        """Сохранить дайджест в БД"""
        from database.models import Digest
        import json

        digest = Digest(
            period_start=digest_data['period_start'],
            period_end=digest_data['period_end'],
            week_number=digest_data['week_number'],
            year=digest_data['year'],
            content=json.dumps(digest_data['content'], ensure_ascii=False),
            digest_text=digest_data['text'],
            status=status,
        )

        self.session.add(digest)
        await self.session.commit()
        await self.session.refresh(digest)

        logger.info(f"💾 Дайджест сохранён: ID={digest.id}, статус={status}")
        return digest.id

    async def update_digest_status(self, digest_id: int, status: str, **kwargs) -> bool:
        """Обновить статус дайджеста"""
        from database.models import Digest

        digest = await self.session.get(Digest, digest_id)
        if not digest:
            logger.error(f"❌ Дайджест ID={digest_id} не найден")
            return False

        digest.status = status

        if status == 'approved':
            digest.approved_at = datetime.utcnow()
            digest.approved_by = kwargs.get('approved_by')
        elif status == 'rejected':
            digest.rejected_by = kwargs.get('rejected_by')
            digest.rejection_reason = kwargs.get('rejection_reason', '')
        elif status == 'sent':
            digest.sent_at = datetime.utcnow()
            digest.message_id = kwargs.get('message_id')

        await self.session.commit()
        logger.info(f"🔄 Дайджест ID={digest_id}: статус → {status}")
        return True

    async def update_digest_text(self, digest_id: int, new_text: str) -> bool:
        """Редактировать текст дайджеста"""
        from database.models import Digest

        digest = await self.session.get(Digest, digest_id)
        if not digest:
            return False

        digest.digest_text = new_text
        await self.session.commit()
        return True

    async def get_pending_digests(self) -> List[Dict]:
        """Получить дайджесты ожидающие утверждения"""
        from database.models import Digest

        stmt = (
            select(Digest)
            .where(Digest.status == 'pending_approval')
            .order_by(Digest.created_at.desc())
        )
        result = await self.session.execute(stmt)
        digests = list(result.scalars().all())

        return [
            {
                'id': d.id,
                'week': d.week_number,
                'year': d.year,
                'period_label': d.period_label,
                'status': d.status,
                'status_emoji': d.status_emoji,
                'created_at': d.created_at.strftime('%d.%m.%Y %H:%M'),
                'text': d.digest_text or '',
            }
            for d in digests
        ]

    async def get_digest_archive(self, limit: int = 50) -> List[Dict]:
        """Получить архив дайджестов"""
        from database.models import Digest

        stmt = (
            select(Digest)
            .order_by(Digest.year.desc(), Digest.week_number.desc())
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        digests = list(result.scalars().all())

        return [
            {
                'id': d.id,
                'week': d.week_number,
                'year': d.year,
                'period_label': d.period_label,
                'status': d.status,
                'status_emoji': d.status_emoji,
                'sent_at': d.sent_at.strftime('%d.%m.%Y %H:%M') if d.sent_at else '-',
                'approved_by': d.approved_by,
                'rejected_reason': d.rejection_reason,
            }
            for d in digests
        ]
