import os
from typing import Dict, Any, List
from datetime import datetime

from sqlalchemy.orm import Session

from .spotify_client import SpotifyClient
from .reccobeats_client import ReccoBeatsClient
from .narrative_service import NarrativeService


class PlaylistService:
    def __init__(
        self,
        db: Session,
        spotify_client: SpotifyClient,
        recco_client: ReccoBeatsClient,
        narrative_service: NarrativeService,
    ) -> None:
        self.db = db
        self.spotify = spotify_client
        self.recco = recco_client
        self.narrative = narrative_service

    async def ensure_playlists_exist(self, user_id: str) -> Dict[str, str]:
        """Check/create playlists. Returns {six_hour_id, daily_id}."""
        six_hour_env = os.getenv("SIX_HOUR_PLAYLIST_ID")
        daily_env = os.getenv("DAILY_PLAYLIST_ID")

        if not six_hour_env:
            six_hour_data = await self.spotify.create_playlist(
                user_id=user_id,
                name="Short and Sweet",
                description="AI-curated 6-hour playlists based on your listening habits",
            )
            six_hour_env = str(six_hour_data["id"])

        if not daily_env:
            daily_data = await self.spotify.create_playlist(
                user_id=user_id,
                name="Proof of Commitment",
                description="Your daily 24-hour mix showing your music journey",
            )
            daily_env = str(daily_data["id"])

        return {"six_hour_id": str(six_hour_env), "daily_id": str(daily_env)}

    async def curate_six_hour_playlist(
        self, period_start: datetime, period_end: datetime
    ) -> Dict[str, Any]:
        """Generate 6-hour playlist (15 curated + 15 recommendations)."""
        from app.models import Track
        from app.services.stats_service import StatsService

        stats = StatsService(self.db)
        data = stats.generate_full_report(period_start, period_end)

        listening_data = {
            "peak_hour": data["time_habits"]["peak_hour"],
            "avg_energy": data["vibe"]["avg_energy"],
            "avg_valence": data["vibe"]["avg_valence"],
            "total_plays": data["volume"]["total_plays"],
            "top_artists": data["volume"]["top_artists"][:10],
        }

        theme_result = self.narrative.generate_playlist_theme(listening_data)

        curated_track_names = theme_result.get("curated_tracks", [])
        curated_tracks: List[str] = []
        for name in curated_track_names:
            track = self.db.query(Track).filter(Track.name.ilike(f"%{name}%")).first()
            if track:
                curated_tracks.append(str(track.id))

        recommendations: List[str] = []
        if curated_tracks:
            recs = await self.recco.get_recommendations(
                seed_ids=curated_tracks[:5],
                size=15,
            )
            recommendations = [
                str(r.get("spotify_id") or r.get("id"))
                for r in recs
                if r.get("spotify_id") or r.get("id")
            ]

        final_tracks = curated_tracks[:15] + recommendations[:15]

        playlist_id = os.getenv("SIX_HOUR_PLAYLIST_ID")
        if playlist_id:
            await self.spotify.update_playlist_details(
                playlist_id=playlist_id,
                name=f"Short and Sweet - {theme_result['theme_name']}",
                description=(
                    f"{theme_result['description']}\n\nCurated: {len(curated_tracks)} tracks + {len(recommendations)} recommendations"
                ),
            )
            await self.spotify.replace_playlist_tracks(
                playlist_id=playlist_id,
                track_uris=[f"spotify:track:{tid}" for tid in final_tracks],
            )

        return {
            "playlist_id": playlist_id,
            "theme_name": theme_result["theme_name"],
            "description": theme_result["description"],
            "track_count": len(final_tracks),
            "curated_count": len(curated_tracks),
            "rec_count": len(recommendations),
            "refreshed_at": datetime.utcnow().isoformat(),
        }

    async def curate_daily_playlist(
        self, period_start: datetime, period_end: datetime
    ) -> Dict[str, Any]:
        """Generate 24-hour playlist (30 favorites + 20 discoveries)."""
        from app.models import Track
        from app.services.stats_service import StatsService

        stats = StatsService(self.db)
        data = stats.generate_full_report(period_start, period_end)

        top_all_time = self._get_top_all_time_tracks(limit=30)
        recent_tracks = [track["id"] for track in data["volume"]["top_tracks"][:20]]

        final_tracks = (top_all_time + recent_tracks)[:50]

        playlist_id = os.getenv("DAILY_PLAYLIST_ID")
        theme_name = f"Proof of Commitment - {datetime.utcnow().date().isoformat()}"
        if playlist_id:
            await self.spotify.update_playlist_details(
                playlist_id=playlist_id,
                name=theme_name,
                description=(
                    f"{theme_name} reflects the past 24 hours plus your all-time devotion."
                ),
            )
            await self.spotify.replace_playlist_tracks(
                playlist_id=playlist_id,
                track_uris=[f"spotify:track:{tid}" for tid in final_tracks],
            )

        return {
            "playlist_id": playlist_id,
            "theme_name": theme_name,
            "description": "Daily mix refreshed with your favorites and discoveries.",
            "track_count": len(final_tracks),
            "favorites_count": len(top_all_time),
            "recent_discoveries_count": len(recent_tracks),
            "refreshed_at": datetime.utcnow().isoformat(),
        }

    def _get_top_all_time_tracks(self, limit: int = 30) -> List[str]:
        """Get top tracks by play count from all-time history."""
        from app.models import PlayHistory, Track
        from sqlalchemy import func

        result = (
            self.db.query(Track.id, func.count(PlayHistory.id).label("play_count"))
            .join(PlayHistory, Track.id == PlayHistory.track_id)
            .group_by(Track.id)
            .order_by(func.count(PlayHistory.id).desc())
            .limit(limit)
            .all()
        )

        return [track_id for track_id, _ in result]
