from django.contrib.auth import login
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponse, HttpResponseNotFound, HttpRequest, JsonResponse
from django.urls import reverse_lazy

from .models import *
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import CallbackForm, ProfileForm, UserEditForm, RegistrationForm
from django.utils import timezone
from django.urls import reverse
from datetime import timedelta
from django.db.models import Count, QuerySet
from django.contrib.auth.decorators import login_required, user_passes_test
from django.views.decorators.http import require_GET, require_POST
from django.views.generic import TemplateView, ListView, CreateView, UpdateView, DetailView
from .mixins import PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin
from .services import get_published_queryset, track_page_view
from typing import Any, Dict, Type
from django.template.loader import render_to_string
from django.utils.http import url_has_allowed_host_and_scheme
from blog.models import Comment
from products.models import Order
import os


class BasePageView(PageViewTrackingMixin, MenuContextMixin, TemplateView):
    """
    Базовый класс для всех страниц сайта.
    Включает отслеживание просмотров и контекст меню.
    """
    extra_context = {}


class BaseListView(PageViewTrackingMixin, MenuContextMixin, ListView):
    """
    Базовый класс для всех страниц со списками объектов.
    Включает отслеживание просмотров и контекст меню.
    """
    extra_context = {}

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update(self.extra_context)
        return context

    def render_to_response(self, context, **response_kwargs):
        # Если это AJAX-запрос, возвращаем JSON с HTML фрагментом
        if self.request.headers.get('x-requested-with') == 'XMLHttpRequest':
            # Определяем шаблон для карточек
            cards_template = getattr(self, 'cards_template', None)
            if not cards_template:
                # Генерируем имя по умолчанию: app/includes/model_cards.html
                cards_template = f"{self.model._meta.app_label}/includes/{self.model._meta.model_name}_cards.html"

            html = render_to_string(
                cards_template,
                {self.context_object_name: context[self.context_object_name]},
                request=self.request
            )
            return JsonResponse({
                'html': html,
                'has_next': context['page_obj'].has_next() if context.get('page_obj') else False
            })
        # Обычный запрос
        return super().render_to_response(context, **response_kwargs)


class HomePageView(BasePageView):
    """Главная страница с формой обратной связи."""
    template_name = 'programmer/index.html'

    def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
        context = super().get_context_data(**kwargs)
        posts = get_published_queryset(Home)
        form = CallbackForm()

        if self.request.user.is_authenticated:
            if 'captcha' in form.fields:
                del form.fields['captcha']

        context.update({
            'posts': posts,
            'form': form,

            'title': "SNA Tecnology - разработка и сопровождение",
            'meta_description': (
                "Профессиональный программист 1С с более чем 10-летним опытом. "
                "Разработка, доработка, обновление и интеграция систем 1С. Сопровождение 1С."
            ),
            'meta_keywords': (
                "программист 1С, разработка 1С, обновление 1С, сопровождение 1С, "
                "интеграция 1С, доработка 1С, 1С предприятие 8.3"
            ),
        })
        return context


class AboutPageView(BasePageView, BreadcrumbMixin):
    """Страница 'О себе'."""
    template_name = 'programmer/about.html'

    def get_breadcrumbs(self):
        return [{'title': 'О нас', 'url_name': None}]

    def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
        context = super().get_context_data(**kwargs)
        form = CallbackForm()

        context.update({
            'form': form,
            'title': "С.Н.А. Технологии — Профессиональная разработка и сопровождение 1С",
            'meta_description': (
                "Команда экспертов по автоматизации бизнеса на платформе 1С. "
                "Разработка, доработка, интеграция и поддержка 1С для компаний любого масштаба. "
                "Официальный договор, опыт более 10 лет."
            ),
            'meta_keywords': (
                "разработка 1С, сопровождение 1С, автоматизация бизнеса 1С, "
                "интеграция 1С, программист 1С компания, СНА Технологии, обновление 1С, 1С под ключ"            
            ),
        })
        return context


class SolutionListView(BaseListView, BreadcrumbMixin):
    """Список проектов с пагинацией."""
    model = Solution
    template_name = 'programmer/solution.html'
    context_object_name = 'posts'
    paginate_by = 5  # Количество проектов на странице
    cards_template = 'programmer/includes/project_cards.html'
    ordering = ['-time_create']

    def get_breadcrumbs(self):
        return [{'title': 'Проекты', 'url_name': None}]

    def get_queryset(self) -> QuerySet:
        """Возвращает только опубликованные проекты."""
        return get_published_queryset(self.model, order_by='-time_create')

    def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
        context = super().get_context_data(**kwargs)
        form = CallbackForm()

        context.update({
            'form': form,
            'title': "Проекты автоматизации 1С | Реализованные кейсы и решения",
            'meta_description': (
                "Реализованные проекты по автоматизации 1С: складской учет с ТСД, "
                "интеграция с оборудованием, миграция с 1С 7.7. Примеры работ и кейсы."
            ),
            'meta_keywords': (
                "проекты 1С, автоматизация склада 1С, интеграция ТСД 1С, "
                "миграция 1С 7.7, кейсы 1С, примеры работ 1С"
            ),
        })
        return context


class RecallListView(BaseListView, BreadcrumbMixin):
    """Список отзывов с пагинацией."""
    model = Recall
    template_name = 'programmer/recall.html'
    context_object_name = 'posts'
    paginate_by = 5
    ordering = ['-time_create']

    def get_breadcrumbs(self):
        return [{'title': 'Отзывы', 'url_name': None}]

    def get_queryset(self) -> QuerySet:
        """Возвращает только опубликованные отзывы."""
        return get_published_queryset(self.model, order_by='-time_create')

    def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
        context = super().get_context_data(**kwargs)
        form = CallbackForm()

        context.update({
            'form': form,
            'title': "Отзывы клиентов о работе программиста 1С | Реальные кейсы",
            'meta_description': (
                "Реальные отзывы клиентов о работе программиста 1С Николая Сердюка. "
                "Отзывы от ООО «РОВЕН-Регионы» и других компаний."
            ),
            'meta_keywords': (
                "отзывы программист 1С, рекомендации 1С, отзывы клиентов 1С, "
                "реальные кейсы 1С, отзыв ООО РОВЕН"
            ),
        })
        return context


class ProfileView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin, TemplateView):
    template_name = 'programmer/profile.html'

    def get_breadcrumbs(self):
        return [{'title': 'Профиль', 'url_name': None}]


class RegisterView(PageViewTrackingMixin, MenuContextMixin, SuccessMessageMixin, BreadcrumbMixin, CreateView):
    """Регистрация нового пользователя"""
    template_name = 'programmer/register.html'
    form_class = RegistrationForm
    # success_url = reverse_lazy('profile')
    success_message = '✅ Регистрация успешна!'

    def get_breadcrumbs(self):
        return [{'title': 'Регистрация', 'url_name': None}]

    def get_success_url(self):
        # Если есть параметр next, используем его
        next_url = self.request.POST.get('next') or self.request.GET.get('next')
        if next_url:
            return next_url
        return reverse_lazy('profile')

    def form_valid(self, form):
        # Сохраняем пользователя
        response = super().form_valid(form)
        # Автоматически логиним после регистрации
        user = self.object
        login(self.request, user)
        return response

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['next'] = self.request.GET.get('next', '')
        context.update({
            'title': "Регистрация | СНА Технологии",
        })

        return context
    
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super().__init__(*args, **kwargs)


class ProfileEditView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin, UpdateView):
    model = Profile
    form_class = ProfileForm
    template_name = 'programmer/profile_edit.html'
    success_url = reverse_lazy('profile')

    def get_breadcrumbs(self):
        return [
            {'title': 'Профиль', 'url_name': 'profile'},
            {'title': 'Редактирование', 'url_name': None},
        ]

    def get_object(self, queryset=None):
        # Возвращаем профиль текущего пользователя
        return self.request.user.profile

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Передаём формы в контекст
        if 'user_form' not in context:
            context['user_form'] = UserEditForm(instance=self.request.user)
        if 'profile_form' not in context:
            context['profile_form'] = ProfileForm(instance=self.request.user.profile)
        return context

    def post(self, request, *args, **kwargs):
        user_form = UserEditForm(request.POST, instance=request.user)
        profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)

        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, '✅ Профиль успешно обновлён.')
            return redirect('profile')
        else:
            # Если формы не валидны, показываем ошибки
            context = self.get_context_data()
            context['user_form'] = user_form
            context['profile_form'] = profile_form
            return self.render_to_response(context)


class PrivacyPolicyView(TemplateView, MenuContextMixin, BreadcrumbMixin):
    template_name = 'programmer/privacy.html'

    def get_breadcrumbs(self):
        return [{'title': 'Политика конфиденциальности', 'url_name': None}]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'title': "Политика конфиденциальности | С.Н.А. Технологии",
        })

        return context


class SolutionDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
    model = Solution
    template_name = 'programmer/solution_detail.html'
    context_object_name = 'solution'
    # Отображаются только опубликованные объекты; для неопубликованных выводится ошибка 404
    queryset = Solution.objects.filter(is_published=True)

    def get_breadcrumbs(self):
        return [
        {'title': 'Проекты', 'url_name': 'solution'},
        {'title': self.object.title, 'url_name': None},
        ]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = self.object.get_seo_title()
        context['meta_description'] = self.object.get_seo_description()
        return context


class RecallDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
    model = Recall
    template_name = 'programmer/recall_detail.html'
    context_object_name = 'recall'
    queryset = Recall.objects.filter(is_published=True)

    def get_breadcrumbs(self):
        return [
        {'title': 'Отзывы', 'url_name': 'recall'},
        {'title': self.object.title, 'url_name': None},
        ]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = self.object.get_seo_title()
        context['meta_description'] = self.object.get_seo_description()
        return context


class CompetenceDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
    model = Competence
    template_name = 'programmer/competence_detail.html'
    context_object_name = 'competence'
    queryset = Competence.objects.filter(is_published=True)

    def get_breadcrumbs(self):
        return [
        {'title': 'Компетенции', 'url_name': 'ability'},
        {'title': self.object.title, 'url_name': None},
        ]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context



class RequisitesPageView(BasePageView, BreadcrumbMixin):
    """Страница с реквизитами компании."""
    template_name = 'programmer/requisites.html'

    def get_breadcrumbs(self):
        return [
            {'title': 'О компании', 'url_name': 'about'},
            {'title': 'Реквизиты', 'url_name': None}
        ]

    def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
        context = super().get_context_data(**kwargs)
        context.update({
            'title': "Реквизиты ИП Сердюк Н.А. | С.Н.А. Технологии",
            'meta_description': (
                "Официальные реквизиты ИП Сердюк Николай Александрович. "
                "ИНН, ОГРНИП, банковские реквизиты для выставления счетов и заключения договоров."
            ),
            'meta_keywords': "реквизиты ИП, Сердюк Николай Александрович, СНА Технологии, ИНН, ОГРНИП",
            'RQ_INN': os.getenv('RQ_INN', 'не указан'),
            'RQ_OGRNIP': os.getenv('RQ_OGRNIP', 'не указан'),
            'RQ_ADRES': os.getenv('RQ_ADRES', 'не указан'),
            'RQ_ECENT': os.getenv('RQ_ECENT', 'не указан'),
            'RQ_BANK': os.getenv('RQ_BANK', 'не указан'),
            'RQ_BIK': os.getenv('RQ_BIK', 'не указан'),
            'RQ_KOR_ECENT': os.getenv('RQ_KOR_ECENT', 'не указан'),
        })
        return context


@require_POST
def callback_request(request: HttpRequest) -> HttpResponse:
    """
    Обработка заявки на обратный звонок.
    Принимает только POST запросы.
    """
    form = CallbackForm(request.POST)

    if request.user.is_authenticated:
        if 'captcha' in form.fields:
            del form.fields['captcha']

    next_url = request.POST.get('next', '')
    if not next_url or not url_has_allowed_host_and_scheme(next_url, allowed_hosts={request.get_host()}):
        next_url = reverse('home')

    if form.is_valid():
        # Сохраняем заявку
        callback = form.save()

        # TODO: В будущем можно добавить асинхронную отправку email через Celery
        # from .tasks import send_callback_email
        # send_callback_email.delay(callback.id)

        messages.success(
            request,
            '✅ Ваша заявка успешно отправлена! Мы свяжемся с вами в ближайшее время.'
        )
    else:
        # Собираем все ошибки формы
        for field, errors in form.errors.items():
            field_label = form.fields[field].label if field in form.fields else field
            for error in errors:
                messages.error(
                    request,
                    f'❌ Ошибка в поле "{field_label}": {error}'
                )

    return redirect(next_url)



def pageNotFound(request: HttpRequest, exception: Exception) -> HttpResponseNotFound:
    """Обработчик 404 ошибки."""
    return HttpResponseNotFound('<h1>Страница не найдена</h1>')


def is_staff_user(user) -> bool:
    """Проверка, является ли пользователь сотрудником (для декоратора)."""
    return user.is_staff


@login_required
@user_passes_test(is_staff_user)
def statistics_view(request: HttpRequest) -> HttpResponse:
    """
    Статистика сайта для администраторов.
    TODO: Переделать на класс-based view с отдельным шаблоном.
    """
    today = timezone.now().date()
    week_ago = today - timedelta(days=7)

    # Базовая статистика просмотров
    stats = {
        'today_views': PageView.objects.filter(timestamp__date=today).count(),
        'weekly_views': PageView.objects.filter(timestamp__date__gte=week_ago).count(),
        'total_views': PageView.objects.count(),
        'unique_visitors': Visitor.objects.filter(last_visit__date__gte=week_ago).count(),
    }

    # Популярные страницы за неделю
    stats['popular_pages'] = (
        PageView.objects
        .filter(timestamp__date__gte=week_ago)
        .values('url')
        .annotate(views=Count('id'))
        .order_by('-views')[:10]
    )

    # Последние посещения
    stats['recent_views'] = PageView.objects.order_by('-timestamp')[:20]

    # Статистика заявок
    stats.update({
        'total_callbacks': CallbackRequest.objects.count(),
        'today_callbacks': CallbackRequest.objects.filter(time_create__date=today).count(),
        'unread_callbacks': CallbackRequest.objects.filter(is_read=False).count(),
    })

    return render(request, 'admin/statistics.html', {'stats': stats})


@require_GET
def robots_txt(request):
    """Отдает robots.txt."""
    return render(request, 'programmer/robots.txt', content_type='text/plain')
    return render(request, 'programmer/robots.txt', content_type='text/plain; charset=utf-8')

@require_GET
def yandex_html(request: HttpRequest) -> HttpResponse:
    """Отдает yandex_cdc16c33291495b9.html."""
    return render(request, 'programmer/yandex_cdc16c33291495b9.html', content_type='text/html')

@login_required
def my_callbacks(request):
    callbacks = CallbackRequest.objects.filter(email=request.user.email).order_by('-time_create')
    # Можно также фильтровать по телефону, если он заполнен в профиле, но email — универсальнее.
    orders = Order.objects.filter(email=request.user.email).order_by('-created_at')  # если поле есть
    return render(request, 'programmer/includes/my_callbacks.html', {
        'callbacks': callbacks,
        'orders': orders,
    })

@login_required
def my_comments(request):
    comments = Comment.objects.filter(user=request.user).select_related('article').order_by('-time_create')
    return render(request, 'programmer/includes/my_comments.html', {'comments': comments})

@login_required
def notification_settings(request):
    profile = request.user.profile
    if request.method == 'POST':
        # обработка формы (можно через AJAX POST)
        profile.notify_new_articles = request.POST.get('notify_new_articles') == 'on'
        profile.notify_new_products = request.POST.get('notify_new_products') == 'on'
        profile.save()
        return JsonResponse({'status': 'ok'})
    return render(request, 'programmer/includes/notification_settings.html', {'profile': profile})
