from django.core.mail import send_mail
from django.conf import settings
from django.template.loader import render_to_string
from django.utils import timezone
from settingspanel.models import AppSettings
# from accounts.utils import JellyfinClient  # not needed for availability; use Sonarr/Radarr instead
import requests
from dateutil.parser import isoparse
import logging

logger = logging.getLogger(__name__)

def _set_runtime_email_settings():
    app_settings = AppSettings.current()
    sec = (app_settings.mail_secure or '').strip().lower()
    use_tls = sec in ('tls', 'starttls', 'start_tls', 'tls1.2', 'tls1_2')
    use_ssl = sec in ('ssl', 'smtps')
    # Prefer SSL over TLS if both matched somehow
    if use_ssl:
        use_tls = False

    # Apply email settings dynamically for this process
    settings.EMAIL_HOST = (app_settings.mail_host or settings.EMAIL_HOST)
    # Port defaults if not provided
    if app_settings.mail_port:
        settings.EMAIL_PORT = int(app_settings.mail_port)
    else:
        if use_ssl and not settings.EMAIL_PORT:
            settings.EMAIL_PORT = 465
        elif use_tls and not settings.EMAIL_PORT:
            settings.EMAIL_PORT = 587

    settings.EMAIL_USE_TLS = use_tls
    settings.EMAIL_USE_SSL = use_ssl

    settings.EMAIL_HOST_USER = app_settings.mail_user or settings.EMAIL_HOST_USER
    settings.EMAIL_HOST_PASSWORD = app_settings.mail_password or settings.EMAIL_HOST_PASSWORD

    # From email fallback
    if app_settings.mail_from:
        settings.DEFAULT_FROM_EMAIL = app_settings.mail_from
    elif not getattr(settings, 'DEFAULT_FROM_EMAIL', None):
        host = (settings.EMAIL_HOST or 'localhost')
        settings.DEFAULT_FROM_EMAIL = f'noreply@{host}'

    # return summary for debugging
    return {
        'host': settings.EMAIL_HOST,
        'port': settings.EMAIL_PORT,
        'use_tls': settings.EMAIL_USE_TLS,
        'use_ssl': settings.EMAIL_USE_SSL,
        'from_email': settings.DEFAULT_FROM_EMAIL,
        'auth_user_set': bool(settings.EMAIL_HOST_USER),
    }


def send_notification_email(
    user,
    media_title,
    media_type,
    overview=None,
    poster_url=None,
    episode_title=None,
    season=None,
    episode=None,
    air_date=None,
    year=None,
    release_type=None,
):
    """
    Sends a notification email to a user with extended details
    """
    eff = _set_runtime_email_settings()
    logger.info(
        "Email settings: host=%s port=%s tls=%s ssl=%s from=%s auth_user_set=%s",
        eff['host'], eff['port'], eff['use_tls'], eff['use_ssl'], eff['from_email'], eff['auth_user_set']
    )

    # Format air date if provided
    air_date_str = None
    if air_date:
        try:
            from dateutil.parser import isoparse as _iso
            dt = _iso(air_date) if isinstance(air_date, str) else air_date
            try:
                tz = timezone.get_current_timezone()
                dt = dt.astimezone(tz)
            except Exception:
                pass
            air_date_str = dt.strftime('%d.%m.%Y %H:%M')
        except Exception:
            air_date_str = str(air_date)

    context = {
        'username': user.username,
        'title': media_title,
    'type': 'Series' if media_type == 'series' else 'Movie',
        'overview': overview,
        'poster_url': poster_url,
        'episode_title': episode_title,
        'season': season,
        'episode': episode,
        'air_date': air_date_str,
        'year': year,
        'release_type': release_type,
    }

    subject = f"New {context['type']} available: {media_title}"
    message = render_to_string('arr_api/email/new_media_notification.html', context)

    send_mail(
        subject=subject,
        message=message,
        from_email=settings.DEFAULT_FROM_EMAIL,
        recipient_list=[user.email],
        html_message=message,
        fail_silently=False,
    )


def _get_arr_cfg():
    cfg = AppSettings.current()
    return {
        'sonarr_url': (cfg.sonarr_url or '').strip(),
        'sonarr_key': (cfg.sonarr_api_key or '').strip(),
        'radarr_url': (cfg.radarr_url or '').strip(),
        'radarr_key': (cfg.radarr_api_key or '').strip(),
    }


def _sonarr_get(url_base, api_key, path, params=None, timeout=10):
    if not url_base or not api_key:
        return None
    url = f"{url_base.rstrip('/')}{path}"
    try:
        r = requests.get(url, headers={"X-Api-Key": api_key}, params=params or {}, timeout=timeout)
        r.raise_for_status()
        return r.json()
    except requests.RequestException:
        return None


def _radarr_get(url_base, api_key, path, params=None, timeout=10):
    if not url_base or not api_key:
        return None
    url = f"{url_base.rstrip('/')}{path}"
    try:
        r = requests.get(url, headers={"X-Api-Key": api_key}, params=params or {}, timeout=timeout)
        r.raise_for_status()
        return r.json()
    except requests.RequestException:
        return None


def sonarr_episode_has_file(series_id: int, season: int, episode: int) -> bool:
    cfg = _get_arr_cfg()
    data = _sonarr_get(cfg['sonarr_url'], cfg['sonarr_key'], "/api/v3/episode", params={"seriesId": series_id}) or []
    for ep in data:
        if ep.get("seasonNumber") == season and ep.get("episodeNumber") == episode:
            return bool(ep.get("hasFile"))
    return False


def radarr_movie_has_file(movie_id: int) -> bool:
    cfg = _get_arr_cfg()
    data = _radarr_get(cfg['radarr_url'], cfg['radarr_key'], f"/api/v3/movie/{movie_id}")
    if not data:
        return False
    return bool(data.get("hasFile"))


def get_todays_sonarr_calendar():
    from .services import sonarr_calendar
    cfg = _get_arr_cfg()
    items = sonarr_calendar(days=1, base_url=cfg['sonarr_url'], api_key=cfg['sonarr_key']) or []
    today = timezone.now().date()
    todays = []
    for it in items:
        try:
            ad = isoparse(it.get("airDateUtc")) if it.get("airDateUtc") else None
            if ad and ad.date() == today:
                todays.append(it)
        except Exception:
            pass
    return todays


def get_todays_radarr_calendar():
    from .services import radarr_calendar
    cfg = _get_arr_cfg()
    items = radarr_calendar(days=1, base_url=cfg['radarr_url'], api_key=cfg['radarr_key']) or []
    today = timezone.now().date()
    todays = []
    for it in items:
        # consider any of the dates equal today
        for k in ("inCinemas", "physicalRelease", "digitalRelease"):
            v = it.get(k)
            if not v:
                continue
            try:
                d = isoparse(v).date()
                if d == today:
                    todays.append(it)
                    break
            except Exception:
                continue
    return todays


def check_jellyfin_availability(user, media_id, media_type):
    """
    Replaced: We check availability via Sonarr/Radarr (hasFile),
    which is reliable if Jellyfin scans the same folders.
    """
    # user is unused here; kept for backward compatibility
    if media_type == 'series':
        # cannot decide without season/episode here; will be handled in main loop
        return False
    else:
        return radarr_movie_has_file(media_id)


def check_and_notify_users():
    """
    Hauptfunktion die periodisch aufgerufen wird.
    Prüft neue Medien und sendet Benachrichtigungen.
    """
    from .models import SeriesSubscription, MovieSubscription, SentNotification

    # calendars for today
    todays_series = get_todays_sonarr_calendar()
    todays_movies = get_todays_radarr_calendar()

    # index by ids for quick lookup
    series_idx = {}
    for it in todays_series:
        sid = it.get("seriesId")
        if not sid:
            continue
        series_idx.setdefault(sid, []).append(it)

    movie_idx = {it.get("movieId"): it for it in todays_movies if it.get("movieId")}

    today = timezone.now().date()

    # Serien-Abos
    for sub in SeriesSubscription.objects.select_related('user').all():
        if sub.series_id not in series_idx:
            continue
        # iterate today's episodes for this series
        for ep in series_idx[sub.series_id]:
            season = ep.get("seasonNumber")
            number = ep.get("episodeNumber")
            if season is None or number is None:
                continue

            # duplicate guard (per series per day per user)
            if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
                already_notified = SentNotification.objects.filter(
                    media_id=sub.series_id,
                    media_type='series',
                    air_date=today,
                    user=sub.user
                ).exists()
                if already_notified:
                    continue

            # check availability via Sonarr hasFile
            if sonarr_episode_has_file(sub.series_id, season, number):
                if not sub.user.email:
                    continue
                send_notification_email(
                    user=sub.user,
                    media_title=sub.series_title,
                    media_type='series',
                    overview=sub.series_overview,
                    poster_url=ep.get('seriesPoster'),
                    episode_title=ep.get('title'),
                    season=season,
                    episode=number,
                    air_date=ep.get('airDateUtc'),
                )
                # mark as sent unless duplicates are allowed
                if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
                    SentNotification.objects.create(
                        user=sub.user,
                        media_id=sub.series_id,
                        media_type='series',
                        media_title=sub.series_title,
                        air_date=today
                    )

    # Film-Abos
    for sub in MovieSubscription.objects.select_related('user').all():
        it = movie_idx.get(sub.movie_id)
        if not it:
            continue

        if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
            already_notified = SentNotification.objects.filter(
                media_id=sub.movie_id,
                media_type='movie',
                air_date=today,
                user=sub.user
            ).exists()
            if already_notified:
                continue

        if radarr_movie_has_file(sub.movie_id):
            if not sub.user.email:
                continue
            # detect which release matched today
            rel = None
            try:
                for key, name in (("digitalRelease", "Digital"), ("physicalRelease", "Disc"), ("inCinemas", "Kino")):
                    v = it.get(key)
                    if not v:
                        continue
                    d = isoparse(v).date()
                    if d == today:
                        rel = name
                        break
            except Exception:
                pass

            send_notification_email(
                user=sub.user,
                media_title=sub.title,
                media_type='movie',
                overview=sub.overview,
                poster_url=it.get('posterUrl'),
                year=it.get('year'),
                release_type=rel,
            )
            if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
                SentNotification.objects.create(
                    user=sub.user,
                    media_id=sub.movie_id,
                    media_type='movie',
                    media_title=sub.title,
                    air_date=today
                )


def has_new_episode_today(series_id):
    """
    Legacy helper no longer used directly.
    """
    return True


def has_movie_release_today(movie_id):
    """
    Legacy helper no longer used directly.
    """
    return True
