import calendar
from collections import defaultdict
from datetime import datetime, time, timedelta

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone

from .forms import EventForm
from .models import Event


PROJECT_NAME = 'Roadshow Calendar'
DEFAULT_META_DESCRIPTION = 'Track where your business will be each day with a polished public calendar and secure staff-only event management.'


def _parse_month(month_value: str | None):
    today = timezone.localdate()
    if month_value:
        try:
            parsed = datetime.strptime(month_value, '%Y-%m').date()
            return parsed.replace(day=1)
        except ValueError:
            pass
    return today.replace(day=1)


def _next_month(month_start):
    return (month_start.replace(day=28) + timedelta(days=4)).replace(day=1)


def _previous_month(month_start):
    return (month_start - timedelta(days=1)).replace(day=1)


def _build_month_context(month_value=None):
    month_start = _parse_month(month_value)
    next_month = _next_month(month_start)
    tz = timezone.get_current_timezone()
    range_start = timezone.make_aware(datetime.combine(month_start, time.min), tz)
    range_end = timezone.make_aware(datetime.combine(next_month, time.min), tz)

    events = list(
        Event.objects.filter(is_published=True, start__lt=range_end, end__gte=range_start).order_by('start', 'name')
    )

    event_map = defaultdict(list)
    for event in events:
        start_local = timezone.localtime(event.start)
        end_local = timezone.localtime(event.end)
        current_day = start_local.date()
        final_day = end_local.date()
        while current_day <= final_day:
            event_map[current_day.isoformat()].append(
                {
                    'name': event.name,
                    'location': event.location,
                    'time': f"{start_local:%I:%M %p} – {end_local:%I:%M %p}" if start_local.date() == end_local.date() else f"{start_local:%b %d, %I:%M %p} – {end_local:%b %d, %I:%M %p}",
                    'summary': event.summary,
                    'event_url': event.event_url,
                    'detail_url': reverse('event_detail', kwargs={'slug': event.slug}),
                }
            )
            current_day += timedelta(days=1)

    month_calendar = calendar.Calendar(firstweekday=6)
    today = timezone.localdate()
    calendar_weeks = []
    for week in month_calendar.monthdatescalendar(month_start.year, month_start.month):
        week_days = []
        for day in week:
            iso = day.isoformat()
            day_events = event_map.get(iso, [])
            week_days.append(
                {
                    'date': day,
                    'iso': iso,
                    'day': day.day,
                    'in_month': day.month == month_start.month,
                    'is_today': day == today,
                    'event_count': len(day_events),
                    'has_events': bool(day_events),
                }
            )
        calendar_weeks.append(week_days)

    return {
        'calendar_weeks': calendar_weeks,
        'calendar_events': dict(event_map),
        'month_label': month_start.strftime('%B %Y'),
        'month_value': month_start.strftime('%Y-%m'),
        'prev_month': _previous_month(month_start).strftime('%Y-%m'),
        'next_month': next_month.strftime('%Y-%m'),
        'today_value': today.strftime('%Y-%m'),
    }


def _base_context(**extra):
    context = {
        'project_name': PROJECT_NAME,
        'meta_description': DEFAULT_META_DESCRIPTION,
    }
    context.update(extra)
    return context


@login_required(login_url='login')
def event_dashboard(request):
    if not request.user.is_staff:
        raise PermissionDenied
    events = Event.objects.all().order_by('start', 'name')
    return render(
        request,
        'core/event_dashboard.html',
        _base_context(
            page_title='Manage events',
            events=events,
            dashboard_count=events.count(),
        ),
    )


@login_required(login_url='login')
def event_create(request):
    if not request.user.is_staff:
        raise PermissionDenied

    if request.method == 'POST':
        form = EventForm(request.POST)
        if form.is_valid():
            event = form.save()
            messages.success(request, 'Event saved and ready for the public calendar.')
            return redirect('event_dashboard_detail', slug=event.slug)
    else:
        form = EventForm()

    return render(
        request,
        'core/event_form.html',
        _base_context(
            page_title='Add event',
            form=form,
            form_mode='create',
            form_title='Add a new stop to the calendar',
            form_intro='Once saved, published events immediately power the landing page, public calendar, and embeddable widget.',
            submit_label='Save event',
        ),
    )


@login_required(login_url='login')
def event_edit(request, slug):
    if not request.user.is_staff:
        raise PermissionDenied

    event = get_object_or_404(Event, slug=slug)
    if request.method == 'POST':
        form = EventForm(request.POST, instance=event)
        if form.is_valid():
            event = form.save()
            messages.success(request, 'Event updated successfully.')
            return redirect('event_dashboard_detail', slug=event.slug)
    else:
        form = EventForm(instance=event)

    return render(
        request,
        'core/event_form.html',
        _base_context(
            page_title=f'Edit {event.name}',
            form=form,
            event=event,
            form_mode='edit',
            form_title='Update this calendar stop',
            form_intro='Change dates, copy, publication status, or the event link without leaving the custom dashboard.',
            submit_label='Save changes',
        ),
    )


@login_required(login_url='login')
def event_delete(request, slug):
    if not request.user.is_staff:
        raise PermissionDenied

    event = get_object_or_404(Event, slug=slug)
    if request.method == 'POST':
        event_name = event.name
        event.delete()
        messages.success(request, f'{event_name} was deleted.')
        return redirect('event_dashboard')

    return render(
        request,
        'core/event_confirm_delete.html',
        _base_context(
            page_title=f'Delete {event.name}',
            event=event,
        ),
    )


@login_required(login_url='login')
def event_dashboard_detail(request, slug):
    if not request.user.is_staff:
        raise PermissionDenied
    event = get_object_or_404(Event, slug=slug)
    return render(
        request,
        'core/event_dashboard_detail.html',
        _base_context(
            page_title=event.name,
            event=event,
        ),
    )


def home(request):
    month_context = _build_month_context(request.GET.get('month'))
    upcoming_events = list(Event.objects.filter(is_published=True, end__gte=timezone.now()).order_by('start', 'name')[:6])
    embed_url = request.build_absolute_uri(reverse('calendar_embed'))
    iframe_snippet = f'<iframe src="{embed_url}" title="Where to find us calendar" width="100%" height="760" style="border:0;border-radius:24px;overflow:hidden;"></iframe>'
    return render(
        request,
        'core/index.html',
        _base_context(
            page_title=PROJECT_NAME,
            hero_events=upcoming_events[:3],
            upcoming_events=upcoming_events,
            embed_url=embed_url,
            iframe_snippet=iframe_snippet,
            **month_context,
        ),
    )


def calendar_page(request):
    month_context = _build_month_context(request.GET.get('month'))
    return render(
        request,
        'core/calendar_page.html',
        _base_context(
            page_title='Public calendar',
            **month_context,
        ),
    )


def calendar_embed(request):
    month_context = _build_month_context(request.GET.get('month'))
    return render(
        request,
        'core/calendar_embed.html',
        _base_context(
            page_title='Embeddable calendar',
            embedded=True,
            **month_context,
        ),
    )


def event_list(request):
    events = Event.objects.filter(is_published=True).order_by('start', 'name')
    return render(
        request,
        'core/event_list.html',
        _base_context(
            page_title='Upcoming events',
            events=events,
        ),
    )


def event_detail(request, slug):
    event = get_object_or_404(Event, slug=slug, is_published=True)
    return render(
        request,
        'core/event_detail.html',
        _base_context(
            page_title=event.name,
            event=event,
        ),
    )
