from datetime import timedelta

from django.contrib.auth import get_user_model
from django.db.models import Q
from django.http import HttpResponse
from django.utils import timezone
from openpyxl import Workbook
from rest_framework import generics, permissions, status
from rest_framework.exceptions import NotFound
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView

from portfolio.models import Achievement, Education, Experience, Project, Skill, StudentProfile
from portfolio.serializers import (
    AchievementSerializer,
    EducationSerializer,
    ExperienceSerializer,
    ProjectSerializer,
    SkillSerializer,
    StudentProfileSerializer,
)
from resume.models import GeneratedResume, ResumeAnalytics, ResumeTemplate

from .admin_serializers import (
    AdminStudentListSerializer,
    AdminUserUpdateSerializer,
    GeneratedResumeShortSerializer,
)

User = get_user_model()


class IsAdminRole(permissions.BasePermission):
    def has_permission(self, request, view):
        u = request.user
        return u.is_authenticated and (
            u.is_superuser or getattr(u, "role", None) == User.Role.ADMIN
        )


class AdminStudentPagination(PageNumberPagination):
    page_size = 12
    page_size_query_param = "page_size"
    max_page_size = 50


class AdminUserListView(generics.ListAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = AdminStudentListSerializer
    pagination_class = AdminStudentPagination

    def get_queryset(self):
        qs = (
            User.objects.filter(role=User.Role.STUDENT, is_active=True)
            .select_related("student_profile")
            .order_by("-date_joined")
        )
        q = self.request.query_params.get("search") or self.request.query_params.get("q")
        if q:
            qs = qs.filter(
                Q(email__icontains=q)
                | Q(username__icontains=q)
                | Q(first_name__icontains=q)
                | Q(last_name__icontains=q)
                | Q(student_profile__first_name__icontains=q)
                | Q(student_profile__last_name__icontains=q)
                | Q(student_profile__student_group__icontains=q)
            )
        verified = self.request.query_params.get("is_verified")
        if verified is not None and verified != "":
            if verified.lower() in ("true", "1", "yes"):
                qs = qs.filter(is_verified=True)
            elif verified.lower() in ("false", "0", "no"):
                qs = qs.filter(is_verified=False)
        ob = self.request.query_params.get("ordering", "-date_joined")
        allowed = ("date_joined", "-date_joined", "email", "-email")
        if ob in allowed:
            qs = qs.order_by(ob)
        else:
            qs = qs.order_by("-date_joined")
        return qs


def _student_user_or_404(pk):
    try:
        return User.objects.get(pk=pk, role=User.Role.STUDENT)
    except User.DoesNotExist:
        raise NotFound("Студент не найден.")


def _ensure_student_profile(user):
    """Портфолио привязано к StudentProfile; при отсутствии записи создаём минимальную (админка / edge cases)."""
    profile, _created = StudentProfile.objects.get_or_create(
        user=user,
        defaults={
            "first_name": (user.first_name or "").strip() or "—",
            "last_name": (user.last_name or "").strip() or "—",
            "student_group": "",
        },
    )
    return profile


def _profile_for_user_id(user_id):
    user = _student_user_or_404(user_id)
    return _ensure_student_profile(user)


class AdminUserDetailView(APIView):
    permission_classes = (IsAdminRole,)

    def get(self, request, pk):
        user = _student_user_or_404(pk)
        profile = StudentProfile.objects.filter(user=user).first()
        data = AdminStudentListSerializer(user, context={"request": request}).data
        data["profile"] = (
            StudentProfileSerializer(profile, context={"request": request}).data
            if profile
            else None
        )
        if profile:
            data["projects"] = ProjectSerializer(
                profile.projects.all().order_by("-id"), many=True
            ).data
            data["skills"] = SkillSerializer(profile.skills.all().order_by("name"), many=True).data
            data["achievements"] = AchievementSerializer(
                profile.achievements.all().order_by("-date"), many=True
            ).data
            data["education"] = EducationSerializer(
                profile.educations.all().order_by("-start_year"), many=True
            ).data
            data["experiences"] = ExperienceSerializer(
                profile.experiences.all().order_by("-start_date"), many=True
            ).data
            data["generated_resumes"] = GeneratedResumeShortSerializer(
                profile.generated_resumes.all().order_by("-created_at")[:50], many=True
            ).data
        else:
            data["projects"] = []
            data["skills"] = []
            data["achievements"] = []
            data["education"] = []
            data["experiences"] = []
            data["generated_resumes"] = []
        return Response(data)

    def put(self, request, pk):
        user = _student_user_or_404(pk)
        ser = AdminUserUpdateSerializer(user, data=request.data, partial=True)
        ser.is_valid(raise_exception=True)
        ser.save()
        prof_in = request.data.get("profile")
        if prof_in and isinstance(prof_in, dict):
            profile, created = StudentProfile.objects.get_or_create(
                user=user,
                defaults={
                    "first_name": prof_in.get("first_name")
                    or user.first_name
                    or "—",
                    "last_name": prof_in.get("last_name") or user.last_name or "—",
                    "student_group": prof_in.get("student_group", "") or "",
                },
            )
            for field in (
                "first_name",
                "last_name",
                "patronymic",
                "phone",
                "birth_date",
                "bio",
                "student_group",
                "specialty",
                "average_grade",
            ):
                if field in prof_in:
                    setattr(profile, field, prof_in[field])
            profile.save()
        return self.get(request, pk)

    def delete(self, request, pk):
        user = _student_user_or_404(pk)
        user.is_active = False
        user.save(update_fields=["is_active"])
        return Response(status=status.HTTP_204_NO_CONTENT)


class AdminVerifyUserView(APIView):
    permission_classes = (IsAdminRole,)

    def put(self, request, pk):
        return self._verify(request, pk)

    def post(self, request, pk):
        return self._verify(request, pk)

    def _verify(self, request, pk):
        user = _student_user_or_404(pk)
        user.is_verified = True
        user.save(update_fields=["is_verified"])
        return Response({"detail": "Студент подтверждён.", "id": user.id})


class AdminExportStudentsXlsxView(APIView):
    permission_classes = (IsAdminRole,)

    def get(self, request):
        from io import BytesIO

        wb = Workbook()
        ws = wb.active
        ws.title = "Студенты"
        headers = [
            "ID",
            "Email",
            "Фамилия",
            "Имя",
            "Группа",
            "Подтверждён",
            "Дата регистрации",
        ]
        ws.append(headers)
        qs = (
            User.objects.filter(role=User.Role.STUDENT, is_active=True)
            .select_related("student_profile")
            .order_by("-date_joined")
        )
        for u in qs:
            try:
                p = u.student_profile
            except StudentProfile.DoesNotExist:
                p = None
            ws.append(
                [
                    u.id,
                    u.email,
                    (p.last_name if p else u.last_name) or "",
                    (p.first_name if p else u.first_name) or "",
                    p.student_group if p else "",
                    "да" if u.is_verified else "нет",
                    u.date_joined.isoformat() if u.date_joined else "",
                ]
            )
        bio = BytesIO()
        wb.save(bio)
        bio.seek(0)
        resp = HttpResponse(
            bio.getvalue(),
            content_type=(
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            ),
        )
        resp["Content-Disposition"] = 'attachment; filename="students_export.xlsx"'
        return resp


# Портфолио студента (админ)
class AdminEducationListCreateView(generics.ListCreateAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = EducationSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.educations.all().order_by("-start_year")

    def perform_create(self, serializer):
        p = _profile_for_user_id(self.kwargs["user_id"])
        serializer.save(student=p)


class AdminEducationDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = EducationSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.educations.all()


class AdminExperienceListCreateView(generics.ListCreateAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = ExperienceSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.experiences.all().order_by("-start_date")

    def perform_create(self, serializer):
        p = _profile_for_user_id(self.kwargs["user_id"])
        serializer.save(student=p)


class AdminExperienceDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = ExperienceSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.experiences.all()


class AdminProjectListCreateView(generics.ListCreateAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = ProjectSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.projects.all().order_by("-id")

    def perform_create(self, serializer):
        p = _profile_for_user_id(self.kwargs["user_id"])
        serializer.save(student=p)


class AdminProjectDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = ProjectSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.projects.all()


class AdminSkillListCreateView(generics.ListCreateAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = SkillSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.skills.all().order_by("name")

    def perform_create(self, serializer):
        p = _profile_for_user_id(self.kwargs["user_id"])
        serializer.save(student=p)


class AdminSkillDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = SkillSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.skills.all()


class AdminAchievementListCreateView(generics.ListCreateAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = AchievementSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.achievements.all().order_by("-date")

    def perform_create(self, serializer):
        p = _profile_for_user_id(self.kwargs["user_id"])
        serializer.save(student=p)


class AdminAchievementDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsAdminRole,)
    serializer_class = AchievementSerializer

    def get_queryset(self):
        p = _profile_for_user_id(self.kwargs["user_id"])
        return p.achievements.all()


class AdminStatsView(APIView):
    permission_classes = (IsAdminRole,)

    def get(self, request):
        total_students = User.objects.filter(role=User.Role.STUDENT, is_active=True).count()
        verified = User.objects.filter(
            role=User.Role.STUDENT, is_active=True, is_verified=True
        ).count()
        pending = User.objects.filter(
            role=User.Role.STUDENT, is_active=True, is_verified=False
        ).count()
        resumes = GeneratedResume.objects.count()
        from django.db.models import Sum as SSum

        agg = ResumeAnalytics.objects.aggregate(
            v=SSum("views_count"), d=SSum("downloads_count")
        )
        templates = ResumeTemplate.objects.filter(is_active=True).count()

        today = timezone.now().date()
        weekly_labels = []
        weekly_counts = []
        for i in range(6, -1, -1):
            d = today - timedelta(days=i)
            weekly_labels.append(d.isoformat())
            c = User.objects.filter(
                role=User.Role.STUDENT,
                date_joined__date=d,
            ).count()
            weekly_counts.append(c)

        recent = AdminStudentListSerializer(
            User.objects.filter(role=User.Role.STUDENT, is_active=True)
            .select_related("student_profile")
            .order_by("-date_joined")[:8],
            many=True,
            context={"request": request},
        ).data

        return Response(
            {
                "students_total": total_students,
                "students_verified": verified,
                "students_pending_verification": pending,
                "students_unverified": pending,
                "generated_resumes_total": resumes,
                "resume_views_total": agg["v"] or 0,
                "resume_downloads_total": agg["d"] or 0,
                "active_templates": templates,
                "weekly_labels": weekly_labels,
                "weekly_new_students": weekly_counts,
                "recent_students": recent,
            }
        )
