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 webapp.models import (koleksi as m_koleksi, master as m_master)
from django.core.exceptions import PermissionDenied

from webapp.models.koleksi import (
    Surat, Suratf, Suratd, Disposisi,
    SuratVersion
)
from webapp.api.surat.serializers import (
    SuratSerializer,
    SuratVersionSerializer
)

from .pagination import CustomPageNumberPagination
from rest_framework.decorators import action

from rest_framework.parsers import MultiPartParser, FormParser
from webapp.views.surat import upload as suratf_upload   # upload handler dari WEB (harus sinkron)


class SuratViewSet(viewsets.ModelViewSet):
    """
    ViewSet lengkap untuk data Surat.
    
    Fitur:
    - GET /api/surat/ → list (paging, search, ordering, filter kategori)
    - GET /api/surat/{pk}/ → detail lengkap
    - POST /api/surat/ → create
    - PUT /api/surat/{pk}/ → update (dengan versioning)
    - DELETE /api/surat/{pk}/ → delete
    - POST /api/surat/{pk}/upload/ → upload lampiran (multi-file)
    - GET /api/surat/{pk}/versions/ → riwayat versi
    - GET /api/surat/{pk}/versions/{version_pk}/ → detail versi
    
    Semua proses upload lampiran API mengikuti mekanisme upload WEB,
    agar path, penamaan file, dan metadata sama.
    """

    # Parser untuk menerima multipart/form-data (file upload)
    parser_classes = [MultiPartParser, FormParser]

    queryset = Surat.objects.all()
    serializer_class = SuratSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = CustomPageNumberPagination

    # Search & ordering bawaan DRF
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]

    # Bidang pencarian
    search_fields = [
        "nomor",
        "pengirim_nama",
        "pengirim_instansi",
        "penerima_nama",
        "penerima_instansi",
        "perihal",
        "jenis",
        "sifat",
    ]

    # Bidang ordering yang diizinkan
    ordering_fields = ["created", "updated", "tanggal", "nomor", "jenis", "sifat"]
    ordering = ["-created"]  # default: terbaru → terlama

    # -------------------------------------------------
    # Tambahan sorting sederhana via ?sort=asc / desc
    # -------------------------------------------------
    def filter_queryset(self, queryset):
        """
        Override filter bawaan DRF untuk menambahkan sorting manual:

            ?sort=asc   → created ascending
            ?sort=desc  → created descending

        Ini tidak menggantikan DRF ordering, hanya melengkapinya.
        """
        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

    # -------------------------------------------------
    # Filter Queryset berdasarkan kategori tambahan
    # -------------------------------------------------
    def get_queryset(self):
        """
        Fitur filter tambahan:
            ?kategori=surat masuk
            ?kategori=surat keluar
            ?status=public/private
            ?jenis=surat tugas / lainnya
        """
        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
    # -------------------------------------------------
    def retrieve(self, request, pk=None):
        """
        Mengambil satu surat dengan relasi lampiran, tujuan, disposisi.
        """
        surat = self.get_object()
        data = SuratSerializer(surat, context={"request": request}).data
        return Response(data)

    # -------------------------------------------------
    # CREATE surat baru
    # -------------------------------------------------
    def create(self, request, *args, **kwargs):
        serializer = SuratSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        surat = serializer.save()

        # === PROSES FILE LAMPIRAN PERTAMA (JIKA ADA) ===
        files = request.FILES.getlist("suratf")
        if files:
            # Tidak ada versioning untuk create pertama kali
            # Hanya langsung upload memakai mekanisme web
            suratf_upload.deploy(request, surat.pk, files)
            suratf_upload.save_surat_version(surat, request.user.pk)

        return Response({
            "id": surat.pk,
            "uploaded": len(files),
            "message": "created"
        }, status=status.HTTP_201_CREATED)

    # -------------------------------------------------
    # UPDATE surat (dan simpan SuratVersion sebelum update)
    # -------------------------------------------------
    def update(self, request, pk=None, *args, **kwargs):
        """
        Saat surat di-update:
        - Simpan versi lama ke tabel SuratVersion
        - Lalu update data terbaru
        """
        surat = self.get_object()

        # Simpan versi sebelum update (riwayat)
        SuratVersion.objects.create(
            pk_surat=surat.pk,
            nomor=surat.nomor,
            tanggal=surat.tanggal,
            pengirim=surat.pengirim,
            pengirim_nama=surat.pengirim_nama,
            pengirim_instansi=surat.pengirim_instansi,
            penerima=surat.penerima,
            penerima_nama=surat.penerima_nama,
            penerima_instansi=surat.penerima_instansi,
            sifat=surat.sifat,
            jenis=surat.jenis,
            perihal=surat.perihal,
            status_surat=surat.status_surat,
            user_input=surat.user_input,
        )

        # Update ke data baru
        serializer = SuratSerializer(surat, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response({"id": surat.pk, "message": "updated"})

    # -------------------------------------------------
    # DELETE surat
    # -------------------------------------------------
    def destroy(self, request, pk=None):
        surat = self.get_object()
        surat.delete()
        return Response({"message": "deleted"}, status=status.HTTP_204_NO_CONTENT)

    # -------------------------------------------------
    # GET daftar versi surat
    # -------------------------------------------------
    @action(detail=True, methods=["get"], url_path="versions")
    def versions(self, request, pk=None):
        """
        Menampilkan seluruh riwayat versi surat (termasuk lampiran di tiap versi).
        """
        get_object_or_404(Surat, pk=pk)
        versions_qs = SuratVersion.objects.filter(pk_surat=pk).order_by("-created")
        serializer = SuratVersionSerializer(versions_qs, many=True, context={"request": request})
        return Response(serializer.data)

    # -------------------------------------------------
    # GET detail satu versi surat
    # -------------------------------------------------
    @action(detail=True, methods=["get"], url_path=r"versions/(?P<version_pk>[^/.]+)")
    def version_detail(self, request, pk=None, version_pk=None):
        """
        Menampilkan satu versi surat + seluruh lampiran versi tersebut.
        """
        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
    # -------------------------------------------------------------
    @action(detail=True, methods=["post"], url_path="upload")
    def upload_files(self, request, pk=None):
        """
        Upload lampiran surat (multi-file) dari API.
        Mekanisme ini HARUS identik dengan Web:
        
        1. pending_delete_ids → soft delete lampiran tertentu
        2. save_surat_version() → simpan versi lama sebelum upload baru
        3. getlist("suratf") → menerima banyak file sekaligus
        4. deploy() → fungsi upload dari WEB, menangani rename, path, metadata
        """
        surat = get_object_or_404(Surat, pk=pk)

        # 1️⃣ Soft delete lampiran lama (jika ada)
        pending_ids = request.data.get("pending_delete_ids", "")
        if pending_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 lampiran baru
        suratf_upload.save_surat_version(surat, request.user.pk)

        # 3️⃣ Ambil semua file (multi-upload)
        files = request.FILES.getlist("suratf")
        if not files:
            return Response({"message": "No files uploaded"}, status=400)

        # 4️⃣ Upload lampiran memakai sistem upload WEB
        #    (penamaan file, folder, metadata, size, type → semua sama)
        suratf_upload.deploy(request, surat.pk, files)

        return Response({
            "message": "Upload success",
            "uploaded": len(files),       # jumlah file yang berhasil
            "deleted": pending_ids,       # id lampiran yang dihapus (soft delete)
        })
    

    # -------------------------------------------------
    # rollback surat
    # -------------------------------------------------
    @action(detail=True, methods=["post"], url_path=r"rollback/(?P<version_id>[^/.]+)")
    def rollback_surat(self, request, pk=None, version_id=None):
        # 1. Ambil surat
        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 = request.user.role if hasattr(request.user, 'role') else request.session.get('role')
        user_pk = request.user.pk if hasattr(request.user, 'pk') else request.session.get('pk')

        if user_role not in allowed_roles and surat.user_input != user_pk:
            raise PermissionDenied("Anda tidak memiliki akses rollback.")

        # 3. Eksekusi rollback
        try:
            suratf_upload.rollback_surat(surat_pk, version_id, 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 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
        )
