import logging

from django.contrib import messages
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.views import View
from django.views.generic import TemplateView

from pricemon.forms import PriceWatcherForm
from pricemon.models import PriceAlert, PriceSnapshot, PriceWatcher

logger = logging.getLogger(__name__)


class DashboardView(TemplateView):
    template_name = 'pricemon/dashboard.html'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        watchers = PriceWatcher.objects.all()
        active_alerts = PriceAlert.objects.filter(dismissed=False).select_related('watcher')
        ctx['watchers'] = watchers
        ctx['total_watchers'] = watchers.count()
        ctx['enabled_watchers_count'] = watchers.filter(enabled=True).count()
        ctx['active_alerts_count'] = active_alerts.count()
        ctx['active_alerts'] = active_alerts[:10]
        return ctx


class WatcherCreateView(View):
    template_name = 'pricemon/watcher_form.html'

    def get(self, request):
        return render(request, self.template_name, {'form': PriceWatcherForm(), 'title': 'Add Watcher'})

    def post(self, request):
        form = PriceWatcherForm(request.POST)
        if form.is_valid():
            watcher = form.save()
            messages.success(request, f'Watcher "{watcher.name}" created.')
            return redirect('pricemon-dashboard')
        return render(request, self.template_name, {'form': form, 'title': 'Add Watcher'})


class WatcherEditView(View):
    template_name = 'pricemon/watcher_form.html'

    def get(self, request, pk):
        watcher = get_object_or_404(PriceWatcher, pk=pk)
        return render(request, self.template_name, {
            'form': PriceWatcherForm(instance=watcher),
            'watcher': watcher,
            'title': f'Edit — {watcher.name}',
        })

    def post(self, request, pk):
        watcher = get_object_or_404(PriceWatcher, pk=pk)
        form = PriceWatcherForm(request.POST, instance=watcher)
        if form.is_valid():
            form.save()
            messages.success(request, f'Watcher "{watcher.name}" updated.')
            return redirect('pricemon-dashboard')
        return render(request, self.template_name, {
            'form': form,
            'watcher': watcher,
            'title': f'Edit — {watcher.name}',
        })


class WatcherDeleteView(View):
    def post(self, request, pk):
        watcher = get_object_or_404(PriceWatcher, pk=pk)
        name = watcher.name
        watcher.delete()
        messages.success(request, f'Watcher "{name}" deleted.')
        return redirect('pricemon-dashboard')


class WatcherToggleEnabledView(View):
    def post(self, request, pk):
        watcher = get_object_or_404(PriceWatcher, pk=pk)
        watcher.enabled = not watcher.enabled
        watcher.save(update_fields=['enabled'])
        state = 'enabled' if watcher.enabled else 'disabled'
        messages.success(request, f'Watcher "{watcher.name}" {state}.')
        return redirect('pricemon-dashboard')


class WatcherHistoryView(TemplateView):
    template_name = 'pricemon/history.html'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        watcher = get_object_or_404(PriceWatcher, pk=kwargs['pk'])
        ctx['watcher'] = watcher
        ctx['snapshots'] = watcher.snapshots.all()[:200]
        return ctx


class CheckNowView(View):
    def post(self, request, pk):
        from pricemon.tasks import check_watcher
        watcher = get_object_or_404(PriceWatcher, pk=pk)
        try:
            check_watcher(watcher.pk)
            watcher.refresh_from_db()
            msg = f'Check complete. Current price: ${watcher.last_price}' if watcher.last_price else 'Check complete (price not detected).'
            if request.headers.get('HX-Request'):
                return JsonResponse({'ok': True, 'message': msg})
            messages.success(request, msg)
        except Exception as exc:
            logger.error(f'Manual check failed for watcher {pk}: {exc}')
            if request.headers.get('HX-Request'):
                return JsonResponse({'ok': False, 'message': str(exc)}, status=500)
            messages.error(request, f'Check failed: {exc}')
        return redirect('pricemon-dashboard')


class AlertsPartialView(View):
    def get(self, request):
        alerts = PriceAlert.objects.filter(dismissed=False).select_related('watcher')[:20]
        return render(request, 'pricemon/_alerts.html', {'alerts': alerts})


class DismissAlertView(View):
    def post(self, request, pk):
        alert = get_object_or_404(PriceAlert, pk=pk)
        alert.dismissed = True
        alert.save(update_fields=['dismissed'])
        if request.headers.get('HX-Request'):
            return HttpResponse('')
        return redirect('pricemon-dashboard')


class ChartDataView(View):
    def get(self, request, pk):
        watcher = get_object_or_404(PriceWatcher, pk=pk)
        snapshots = (
            watcher.snapshots
            .filter(price__isnull=False)
            .values('checked_at', 'price')
            .order_by('checked_at')[:500]
        )
        labels = [s['checked_at'].strftime('%Y-%m-%d %H:%M') for s in snapshots]
        prices = [float(s['price']) for s in snapshots]
        return JsonResponse({'labels': labels, 'prices': prices, 'name': watcher.name})


class TestSelectorView(View):
    def post(self, request):
        from pricemon.scraper import _fetch_with_requests, _fetch_with_playwright, parse_price
        url = request.POST.get('url', '').strip()
        css_selector = request.POST.get('css_selector', '').strip()

        if not url or not css_selector:
            return render(request, 'pricemon/_selector_test_result.html', {
                'error': 'Both URL and CSS selector are required.',
            })

        raw_text, error = _fetch_with_requests(url, css_selector)
        method = 'requests'
        if not raw_text and not error:
            raw_text, error = _fetch_with_playwright(url, css_selector)
            method = 'playwright'

        price = parse_price(raw_text) if raw_text else None
        return render(request, 'pricemon/_selector_test_result.html', {
            'raw_text': raw_text,
            'price': price,
            'error': error,
            'method': method,
        })
