from rest_framework import viewsets, status, filters
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.shortcuts import get_object_or_404
from django.core.exceptions import PermissionDenied

# --- Custom Imports ---
from webapp.models import (koleksi as m_koleksi, master as m_master)
from webapp.models.koleksi import (
    Surat, Suratf, Suratd, Disposisi,
    SuratVersion
)
from webapp.api.surat.serializers import (
    SuratSerializer,
    SuratVersionSerializer
)
from webapp.views.surat import upload as suratf_upload   # upload handler dari WEB
from webapp.common import log_activity                  # ✅ AKTIVITAS LOG
from .pagination import CustomPageNumberPagination

# --- DRF Documentation Imports ---
from rest_framework.decorators import action
from rest_framework.parsers import MultiPartParser, FormParser
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes


class SuratViewSet(viewsets.ModelViewSet):
    """
    ViewSet lengkap untuk data Surat.
    Mengimplementasikan CRUD dan fitur Versioning (SuratVersion) dan Upload File.
    """
    parser_classes = [MultiPartParser, FormParser]
    queryset = Surat.objects.all()
    serializer_class = SuratSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = CustomPageNumberPagination
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = [
        "nomor", "pengirim_nama", "pengirim_instansi", 
        "penerima_nama", "penerima_instansi", "perihal", 
        "jenis", "sifat",
    ]
    ordering_fields = ["created", "updated", "tanggal", "nomor", "jenis", "sifat"]
    ordering = ["-created"]

    # -------------------------------------------------
    # Filter Queryset berdasarkan kategori tambahan
    # -------------------------------------------------
    def filter_queryset(self, queryset):
        queryset = super().filter_queryset(queryset)
        sort_param = self.request.query_params.get("sort")
        if sort_param == "asc":
            queryset = queryset.order_by("created")
        elif sort_param == "desc":
            queryset = queryset.order_by("-created")
        return queryset

    def get_queryset(self):
        qs = Surat.objects.all()

        kategori = self.request.query_params.get("kategori", "").lower()
        if kategori == "surat masuk":
            qs = qs.filter(_type="masuk")
        elif kategori == "surat keluar":
            qs = qs.filter(_type="keluar")

        status_surat = self.request.query_params.get("status")
        if status_surat:
            qs = qs.filter(status_surat=status_surat)

        jenis = self.request.query_params.get("jenis")
        if jenis:
            qs = qs.filter(jenis__iexact=jenis)

        return qs

    # -------------------------------------------------
    # RETRIEVE detail surat (tetap standard)
    # -------------------------------------------------
    def retrieve(self, request, pk=None):
        surat = self.get_object()
        data = SuratSerializer(surat, context={"request": request}).data
        return Response(data)

    # -------------------------------------------------
    # CREATE surat baru
    # -------------------------------------------------
    @extend_schema(summary="Create Surat (with initial versioning)")
    def create(self, request, *args, **kwargs):
        serializer = SuratSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 1. Simpan surat, isi user_input
        surat = serializer.save(user_input=request.user.pk)

        # 2. Proses file lampiran
        files = request.FILES.getlist("suratf")
        if files:
            suratf_upload.deploy(request, surat.pk, files)
            # 3. Simpan versi awal (Versi 1) setelah deploy
        
        suratf_upload.save_surat_version(surat, request.user.pk)

        # 4. Log aktivitas
        log_activity(request, 'create', 'surat', surat.pk, f'Membuat surat baru {surat.nomor}')

        return Response({
            "id": surat.pk,
            "uploaded": len(files),
            "message": "created"
        }, status=status.HTTP_201_CREATED)

    # -------------------------------------------------
    # UPDATE surat (dan simpan SuratVersion sebelum update)
    # -------------------------------------------------
    @extend_schema(summary="Update Surat Metadata (with versioning)")
    def update(self, request, pk=None, *args, **kwargs):
        surat = self.get_object()

        # 1. Simpan versi surat SEBELUM di-update (arsip state lama)
        suratf_upload.save_surat_version(surat, request.user.pk)

        # 2. Update ke data baru
        serializer = SuratSerializer(surat, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        # Update user_input untuk mencatat editor terakhir
        surat = serializer.save(user_input=request.user.pk)
        files = request.FILES.getlist("suratf")
        if files:
            m_koleksi.Suratf.objects.filter(
                pk_surat=surat.pk,
                is_deleted=False
            ).update(is_deleted=True)

            suratf_upload.deploy(request, surat.pk, files)
            log_msg = f'Memperbarui metadata dan mengganti {len(files)} lampiran surat {surat.nomor}'
        else:
            log_msg = f'Memperbarui metadata surat {surat.nomor}' 

        # 3. Log aktivitas
        log_activity(request, 'update', 'surat', surat.pk, log_msg)

        return Response({"id": surat.pk, "message": "updated"})
    
    # -------------------------------------------------
    # DELETE surat
    # -------------------------------------------------
    @extend_schema(summary="Delete Surat")
    def destroy(self, request, pk=None):
        surat = self.get_object()
        surat_nomor = surat.nomor # Ambil nomor sebelum dihapus
        surat.delete()
        
        # 1. Log aktivitas
        log_activity(request, 'delete', 'surat', pk, f'Menghapus surat {surat_nomor}')
        
        return Response({"message": "deleted"}, status=status.HTTP_204_NO_CONTENT)

    # -------------------------------------------------
    # GET daftar versi surat
    # -------------------------------------------------
    @extend_schema(
        summary="List all versions of a Surat",
        responses={200: SuratVersionSerializer(many=True)}
    )
    @action(detail=True, methods=["get"], url_path="versions")
    def versions(self, request, pk=None):
        get_object_or_404(Surat, pk=pk)
        versions_qs = SuratVersion.objects.filter(pk_surat=pk).order_by("-created")
        
        # Menggunakan pagination bawaan
        page = self.paginate_queryset(versions_qs)
        if page is not None:
            serializer = SuratVersionSerializer(page, many=True, context={"request": request})
            return self.get_paginated_response(serializer.data)

        serializer = SuratVersionSerializer(versions_qs, many=True, context={"request": request})
        return Response(serializer.data)

    # -------------------------------------------------
    # GET detail satu versi surat
    # -------------------------------------------------
    @extend_schema(
        summary="Retrieve detail of a specific Surat version",
        parameters=[
            OpenApiParameter(name='version_pk', type=OpenApiTypes.INT, location=OpenApiParameter.PATH, description='Primary Key of the SuratVersion'),
        ],
        responses={200: SuratVersionSerializer}
    )
    @action(detail=True, methods=["get"], url_path=r"versions/(?P<version_pk>[^/.]+)")
    def version_detail(self, request, pk=None, version_pk=None):
        get_object_or_404(Surat, pk=pk)
        version = get_object_or_404(SuratVersion, pk=version_pk, pk_surat=pk)
        serializer = SuratVersionSerializer(version, context={"request": request})
        return Response(serializer.data)

    # -------------------------------------------------------------
    # UPLOAD LAMPIRAN (multi-file) — sinkron dengan mekanisme WEB
    # -------------------------------------------------------------
    @extend_schema(
        summary="Upload new attachments and soft-delete old ones (with versioning)",
        request={
            'multipart/form-data': {
                'type': 'object',
                'properties': {
                    # Gunakan 'format: binary' untuk file upload
                    'suratf': {'type': 'array', 'items': {'type': 'string', 'format': 'binary'}, 'description': 'File lampiran baru (bisa multiple)'},
                    'pending_delete_ids': {'type': 'string', 'description': 'Optional: ID Suratf yang akan di-soft delete (dipisahkan koma, cth: "12,15,20")'},
                },
            }
        },
        responses={200: {"type": "object", "properties": {"message": {"type": "string"}, "uploaded": {"type": "integer"}, "deleted": {"type": "array", "items": {"type": "string"}}}}}
    )
    @action(detail=True, methods=["post"], url_path="upload")
    def upload_files(self, request, pk=None):
        surat = get_object_or_404(Surat, pk=pk)
        
        # 1. Soft delete lampiran lama
        pending_ids = request.data.get("pending_delete_ids", "")
        pending_ids = [pid for pid in pending_ids.split(",") if pid.strip()]
        if pending_ids:
            Suratf.objects.filter(pk__in=pending_ids).update(is_deleted=True)

        # 2. Simpan versi surat SEBELUM upload file baru (arsip state saat ini)
        suratf_upload.save_surat_version(surat, request.user.pk)

        # 3. Ambil file baru
        files = request.FILES.getlist("suratf")
        if not files:
            # Jika tidak ada file baru, hanya ada soft delete
            log_activity(request, 'upload', 'surat', surat.pk, f'Soft delete lampiran surat {surat.nomor} (IDs: {",".join(pending_ids)})')
            return Response({
                "message": "Files soft-deleted successfully, no new files uploaded.",
                "uploaded": 0,
                "deleted": pending_ids,
            }, status=status.HTTP_200_OK)

        # 4. Upload file baru
        suratf_upload.deploy(request, surat.pk, files)
        
        # 5. Update user_input untuk mencatat editor terakhir
        surat.user_input = request.user.pk
        surat.save()

        # 6. Log aktivitas
        log_activity(request, 'upload', 'surat', surat.pk, f'Mengunggah {len(files)} lampiran baru ke surat {surat.nomor}')

        return Response({
            "message": "Upload success",
            "uploaded": len(files),
            "deleted": pending_ids,
        })

    # -------------------------------------------------
    # rollback surat
    # -------------------------------------------------
    @extend_schema(
        summary="Rollback Surat to a specific version",
        parameters=[
            OpenApiParameter(name='version_id', type=OpenApiTypes.INT, location=OpenApiParameter.PATH, description='Primary Key of the SuratVersion to rollback to'),
        ],
        request=None, # Tidak ada request body
        responses={200: {"type": "object", "properties": {"success": {"type": "boolean"}, "message": {"type": "string"}, "surat_id": {"type": "integer"}, "version_id": {"type": "string"}}}}
    )
    @action(detail=True, methods=["post"], url_path=r"rollback/(?P<version_id>[^/.]+)")
    def rollback_surat(self, request, pk=None, version_id=None):
        surat_pk = pk
        try:
            surat = m_koleksi.Surat.objects.get(pk=surat_pk)
        except m_koleksi.Surat.DoesNotExist:
            return Response(
                {"detail": "Surat tidak ditemukan."},
                status=status.HTTP_404_NOT_FOUND
            )

        # 2. Validasi role
        allowed_roles = (
            m_master.Roles.objects
            .exclude(role__startswith="OPERATOR")
            .values_list("role", flat=True)
        )

        user_role = getattr(request.user, 'role', request.session.get('role'))
        user_pk = getattr(request.user, 'pk', request.session.get('pk'))

        if user_role not in allowed_roles and str(surat.user_input) != str(user_pk):
            raise PermissionDenied("Anda tidak memiliki akses rollback.")

        # 3. Eksekusi rollback
        try:
            # Pastikan user_pk diolah sebagai INT
            suratf_upload.rollback_surat(surat_pk, version_id, int(user_pk))
        except Exception as e:
            return Response(
                {"detail": f"Rollback gagal: {str(e)}"},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 4. Log aktivitas
        log_activity(request, 'rollback', 'surat', surat_pk, f'Rollback surat {surat.nomor} ke versi {version_id}')

        return Response(
            {
                "success": True,
                "message": f"Berhasil rollback surat ke versi {version_id}.",
                "surat_id": surat_pk,
                "version_id": version_id
            },
            status=status.HTTP_200_OK
        )