"""
Document Control Service — API Views.
"""
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.core.tenant.middleware import get_current_tenant

from .models import (
    Document,
    DocumentAccess,
    DocumentApproval,
    DocumentAuditLog,
    DocumentCategory,
    DocumentVersion,
    ApprovalStatus,
)
from .serializers import (
    DocumentCategoryListSerializer,
    DocumentCategoryDetailSerializer,
    DocumentCategoryCreateSerializer,
    DocumentListSerializer,
    DocumentDetailSerializer,
    DocumentCreateSerializer,
    DocumentUpdateSerializer,
    DocumentVersionListSerializer,
    DocumentVersionCreateSerializer,
    VersionRevertSerializer,
    VersionCompareSerializer,
    DocumentApprovalListSerializer,
    SubmitForApprovalSerializer,
    ApprovalActionSerializer,
    DocumentAccessListSerializer,
    GrantAccessSerializer,
    DocumentAuditLogSerializer,
)
from .services import (
    CategoryService,
    DocumentService,
    VersionService,
    ApprovalService,
    AccessService,
)


def _get_tenant(request):
    """Get tenant from request or middleware."""
    tenant = getattr(request, 'tenant', None) or get_current_tenant()
    if tenant is None:
        raise ValidationError({'detail': 'Tenant not found'})
    return tenant


def _get_ip(request):
    """Extract client IP from request."""
    x_forwarded = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded:
        return x_forwarded.split(',')[0].strip()
    return request.META.get('REMOTE_ADDR')


# ============================================================================
# Category ViewSet
# ============================================================================

class DocumentCategoryViewSet(viewsets.ModelViewSet):
    """
    CRUD for document categories + tree endpoint.
    """
    permission_classes = [IsAuthenticated]
    filter_backends = [SearchFilter, OrderingFilter]
    search_fields = ['name', 'code']
    ordering_fields = ['sort_order', 'name', 'created_at']
    ordering = ['sort_order', 'name']

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return DocumentCategoryDetailSerializer
        if self.action in ('create', 'update', 'partial_update'):
            return DocumentCategoryCreateSerializer
        return DocumentCategoryListSerializer

    def get_queryset(self):
        tenant = _get_tenant(self.request)
        return DocumentCategory.objects.filter(
            tenant=tenant,
        ).select_related('parent').order_by('sort_order', 'name')

    def perform_create(self, serializer):
        tenant = _get_tenant(self.request)
        serializer.save(tenant=tenant)

    @action(detail=False, methods=['get'])
    def tree(self, request):
        """Return full category tree."""
        tenant = _get_tenant(request)
        categories = CategoryService.get_tree(tenant)
        serializer = DocumentCategoryListSerializer(categories, many=True)
        return Response({'data': serializer.data})


# ============================================================================
# Document ViewSet
# ============================================================================

class DocumentViewSet(viewsets.ModelViewSet):
    """
    CRUD for documents + checkout/checkin/publish/archive actions.
    """
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = ['title', 'code', 'description']
    filterset_fields = ['status', 'category']
    ordering_fields = ['title', 'code', 'status', 'current_version', 'created_at', 'updated_at']
    ordering = ['-created_at']

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return DocumentDetailSerializer
        if self.action == 'create':
            return DocumentCreateSerializer
        if self.action in ('update', 'partial_update'):
            return DocumentUpdateSerializer
        return DocumentListSerializer

    def get_queryset(self):
        tenant = _get_tenant(self.request)
        return DocumentService.list_documents(tenant)

    def perform_create(self, serializer):
        tenant = _get_tenant(self.request)
        DocumentService.create_document(
            tenant=tenant,
            user=self.request.user,
            ip_address=_get_ip(self.request),
            **serializer.validated_data,
        )

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        doc = DocumentService.create_document(
            tenant=tenant,
            user=request.user,
            ip_address=_get_ip(request),
            **serializer.validated_data,
        )
        return Response(
            {'data': DocumentDetailSerializer(doc).data},
            status=status.HTTP_201_CREATED,
        )

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        doc = DocumentService.update_document(
            tenant=tenant,
            document_id=instance.id,
            user=request.user,
            ip_address=_get_ip(request),
            **serializer.validated_data,
        )
        return Response({'data': DocumentDetailSerializer(doc).data})

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        tenant = _get_tenant(request)
        DocumentService.delete_document(
            tenant=tenant,
            document_id=instance.id,
            user=request.user,
            ip_address=_get_ip(request),
        )
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=True, methods=['post'])
    def checkout(self, request, pk=None):
        """Check out a document for exclusive editing."""
        tenant = _get_tenant(request)
        try:
            doc = DocumentService.checkout(
                tenant=tenant,
                document_id=pk,
                user=request.user,
                ip_address=_get_ip(request),
            )
            return Response({'data': DocumentDetailSerializer(doc).data})
        except ValueError as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def checkin(self, request, pk=None):
        """Check in a previously checked-out document."""
        tenant = _get_tenant(request)
        try:
            doc = DocumentService.checkin(
                tenant=tenant,
                document_id=pk,
                user=request.user,
                ip_address=_get_ip(request),
            )
            return Response({'data': DocumentDetailSerializer(doc).data})
        except ValueError as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def publish(self, request, pk=None):
        """Publish (approve) a document."""
        tenant = _get_tenant(request)
        try:
            doc = DocumentService.publish(
                tenant=tenant,
                document_id=pk,
                user=request.user,
                ip_address=_get_ip(request),
            )
            return Response({'data': DocumentDetailSerializer(doc).data})
        except ValueError as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def archive(self, request, pk=None):
        """Archive a document."""
        tenant = _get_tenant(request)
        doc = DocumentService.archive(
            tenant=tenant,
            document_id=pk,
            user=request.user,
            ip_address=_get_ip(request),
        )
        return Response({'data': DocumentDetailSerializer(doc).data})


# ============================================================================
# Version ViewSet
# ============================================================================

class DocumentVersionViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Read-only list of document versions + create/revert/compare actions.
    """
    permission_classes = [IsAuthenticated]
    serializer_class = DocumentVersionListSerializer
    ordering = ['-version_number']

    def get_queryset(self):
        tenant = _get_tenant(self.request)
        document_id = self.kwargs.get('document_pk') or self.request.query_params.get('document_id')
        if document_id:
            return VersionService.list_versions(tenant, document_id)
        return DocumentVersion.objects.filter(tenant=tenant).select_related(
            'document', 'created_by',
        ).order_by('-created_at')

    @action(detail=False, methods=['post'])
    def create_version(self, request):
        """Create a new version for a document."""
        serializer = DocumentVersionCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        document_id = request.data.get('document_id') or self.kwargs.get('document_pk')
        if not document_id:
            return Response(
                {'error': {'message': 'document_id الزامی است.'}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        version = VersionService.create_version(
            tenant=tenant,
            document_id=document_id,
            created_by=request.user,
            ip_address=_get_ip(request),
            **serializer.validated_data,
        )
        return Response(
            {'data': DocumentVersionListSerializer(version).data},
            status=status.HTTP_201_CREATED,
        )

    @action(detail=False, methods=['post'])
    def revert(self, request):
        """Revert a document to a previous version."""
        serializer = VersionRevertSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        document_id = request.data.get('document_id') or self.kwargs.get('document_pk')
        if not document_id:
            return Response(
                {'error': {'message': 'document_id الزامی است.'}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        try:
            version = VersionService.revert_version(
                tenant=tenant,
                document_id=document_id,
                target_version_number=serializer.validated_data['target_version_number'],
                user=request.user,
                ip_address=_get_ip(request),
            )
            return Response({'data': DocumentVersionListSerializer(version).data})
        except Exception as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['post'])
    def compare(self, request):
        """Compare two versions of a document."""
        serializer = VersionCompareSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        document_id = request.data.get('document_id') or self.kwargs.get('document_pk')
        if not document_id:
            return Response(
                {'error': {'message': 'document_id الزامی است.'}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        result = VersionService.compare_versions(
            tenant=tenant,
            document_id=document_id,
            version_a=serializer.validated_data['version_a'],
            version_b=serializer.validated_data['version_b'],
        )
        return Response({'data': result})


# ============================================================================
# Approval ViewSet
# ============================================================================

class DocumentApprovalViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Read-only list of approvals + submit/approve/reject actions.
    """
    permission_classes = [IsAuthenticated]
    serializer_class = DocumentApprovalListSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['status', 'document']

    def get_queryset(self):
        tenant = _get_tenant(self.request)
        return ApprovalService.list_approvals(tenant)

    @action(detail=False, methods=['post'])
    def submit(self, request):
        """Submit a document for approval."""
        serializer = SubmitForApprovalSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        try:
            approval = ApprovalService.submit_for_approval(
                tenant=tenant,
                user=request.user,
                ip_address=_get_ip(request),
                **serializer.validated_data,
            )
            return Response(
                {'data': DocumentApprovalListSerializer(approval).data},
                status=status.HTTP_201_CREATED,
            )
        except Exception as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def approve(self, request, pk=None):
        """Approve a document."""
        serializer = ApprovalActionSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        try:
            approval = ApprovalService.approve(
                tenant=tenant,
                approval_id=pk,
                user=request.user,
                ip_address=_get_ip(request),
                **serializer.validated_data,
            )
            return Response({'data': DocumentApprovalListSerializer(approval).data})
        except ValueError as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def reject(self, request, pk=None):
        """Reject a document."""
        serializer = ApprovalActionSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        try:
            approval = ApprovalService.reject(
                tenant=tenant,
                approval_id=pk,
                user=request.user,
                ip_address=_get_ip(request),
                **serializer.validated_data,
            )
            return Response({'data': DocumentApprovalListSerializer(approval).data})
        except ValueError as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['get'])
    def pending(self, request):
        """Get pending approvals for the current user."""
        tenant = _get_tenant(request)
        approvals = ApprovalService.get_pending_approvals(tenant, approver=request.user)
        serializer = DocumentApprovalListSerializer(approvals, many=True)
        return Response({'data': serializer.data})


# ============================================================================
# Access ViewSet
# ============================================================================

class DocumentAccessViewSet(viewsets.ModelViewSet):
    """
    CRUD for document access rules.
    """
    permission_classes = [IsAuthenticated]
    serializer_class = DocumentAccessListSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['document', 'access_type', 'permission_level']

    def get_queryset(self):
        tenant = _get_tenant(self.request)
        document_id = self.request.query_params.get('document_id')
        if document_id:
            return AccessService.list_access(tenant, document_id)
        return DocumentAccess.objects.filter(tenant=tenant).select_related(
            'user', 'granted_by', 'document',
        ).order_by('-created_at')

    @action(detail=False, methods=['post'])
    def grant(self, request):
        """Grant access to a document."""
        serializer = GrantAccessSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        tenant = _get_tenant(request)
        try:
            access = AccessService.grant_access(
                tenant=tenant,
                granted_by=request.user,
                ip_address=_get_ip(request),
                **serializer.validated_data,
            )
            return Response(
                {'data': DocumentAccessListSerializer(access).data},
                status=status.HTTP_201_CREATED,
            )
        except ValueError as e:
            return Response({'error': {'message': str(e)}}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def revoke(self, request, pk=None):
        """Revoke a specific access rule."""
        tenant = _get_tenant(request)
        AccessService.revoke_access(
            tenant=tenant,
            access_id=pk,
            user=request.user,
            ip_address=_get_ip(request),
        )
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=False, methods=['post'])
    def check(self, request):
        """Check if the current user has access to a document."""
        document_id = request.data.get('document_id')
        required_level = request.data.get('required_level', 'view')
        if not document_id:
            return Response(
                {'error': {'message': 'document_id الزامی است.'}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        tenant = _get_tenant(request)
        has_access = AccessService.check_access(
            tenant=tenant,
            document_id=document_id,
            user=request.user,
            required_level=required_level,
        )
        return Response({'data': {'has_access': has_access}})


# ============================================================================
# Audit Log ViewSet
# ============================================================================

class DocumentAuditLogViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Read-only audit log for documents.
    """
    permission_classes = [IsAuthenticated]
    serializer_class = DocumentAuditLogSerializer
    filter_backends = [DjangoFilterBackend, OrderingFilter]
    filterset_fields = ['document', 'action', 'user']
    ordering_fields = ['created_at']
    ordering = ['-created_at']

    def get_queryset(self):
        tenant = _get_tenant(self.request)
        return DocumentAuditLog.objects.filter(
            tenant=tenant,
        ).select_related('document', 'user').order_by('-created_at')
