"""
Integration tests for complete moderation workflows.

This module tests end-to-end moderation workflows including:
- Submission approval workflow
- Submission rejection workflow
- Submission escalation workflow
- Report handling workflow
- Bulk operation workflow
"""

from datetime import timedelta

from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from django.utils import timezone

User = get_user_model()


class SubmissionApprovalWorkflowTests(TestCase):
    """Tests for the complete submission approval workflow."""

    @classmethod
    def setUpTestData(cls):
        """Set up test data for all tests."""
        cls.regular_user = User.objects.create_user(
            username="regular_user", email="user@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="moderator", email="mod@example.com", password="testpass123", role="MODERATOR"
        )
        cls.admin = User.objects.create_user(
            username="admin", email="admin@example.com", password="testpass123", role="ADMIN"
        )

    def test_edit_submission_approval_workflow(self):
        """
        Test complete edit submission approval workflow.

        Flow: User submits → Moderator claims → Moderator approves → Changes applied
        """
        from apps.moderation.models import EditSubmission
        from apps.parks.models import Company

        # Create target object
        company = Company.objects.create(name="Test Company", description="Original description")

        # User submits an edit
        content_type = ContentType.objects.get_for_model(company)
        submission = EditSubmission.objects.create(
            user=self.regular_user,
            content_type=content_type,
            object_id=company.id,
            submission_type="EDIT",
            changes={"description": "Updated description"},
            status="PENDING",
            reason="Fixing typo",
        )

        self.assertEqual(submission.status, "PENDING")
        self.assertIsNone(submission.handled_by)
        self.assertIsNone(submission.handled_at)

        # Moderator claims the submission first
        submission.transition_to_claimed(user=self.moderator)
        submission.save()

        submission.refresh_from_db()
        self.assertEqual(submission.status, "CLAIMED")

        # Moderator approves
        submission.transition_to_approved(user=self.moderator)
        submission.handled_by = self.moderator
        submission.handled_at = timezone.now()
        submission.save()

        submission.refresh_from_db()
        self.assertEqual(submission.status, "APPROVED")
        self.assertEqual(submission.handled_by, self.moderator)
        self.assertIsNotNone(submission.handled_at)

    def test_photo_submission_approval_workflow(self):
        """
        Test complete photo submission approval workflow.

        Flow: User submits photo → Moderator reviews → Moderator approves → Photo created
        """
        from django_cloudflareimages_toolkit.models import CloudflareImage

        from apps.moderation.models import PhotoSubmission
        from apps.parks.models import Company, Park

        # Create target park
        operator = Company.objects.create(name="Test Operator", roles=["OPERATOR"])
        park = Park.objects.create(
            name="Test Park", slug="test-park", operator=operator, status="OPERATING", timezone="America/New_York"
        )

        # Create mock CloudflareImage for the photo submission
        mock_image = CloudflareImage.objects.create(
            cloudflare_id="test-cf-image-id-12345",
            user=self.regular_user,
            expires_at=timezone.now() + timedelta(days=365),
        )

        # User submits a photo
        content_type = ContentType.objects.get_for_model(park)
        submission = PhotoSubmission.objects.create(
            user=self.regular_user,
            content_type=content_type,
            object_id=park.id,
            status="PENDING",
            photo=mock_image,
            caption="Beautiful park entrance",
        )

        self.assertEqual(submission.status, "PENDING")

        # Moderator claims the submission first (required FSM step)
        submission.claim(user=self.moderator)

        submission.refresh_from_db()
        self.assertEqual(submission.status, "CLAIMED")

        # Moderator approves
        submission.transition_to_approved(user=self.moderator)
        submission.handled_by = self.moderator
        submission.handled_at = timezone.now()
        submission.save()

        submission.refresh_from_db()
        self.assertEqual(submission.status, "APPROVED")


class SubmissionRejectionWorkflowTests(TestCase):
    """Tests for the submission rejection workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.regular_user = User.objects.create_user(
            username="user_rej", email="user_rej@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="mod_rej", email="mod_rej@example.com", password="testpass123", role="MODERATOR"
        )

    def test_edit_submission_rejection_with_reason(self):
        """
        Test rejection workflow with reason.

        Flow: User submits → Moderator rejects with reason → User notified
        """
        from apps.moderation.models import EditSubmission
        from apps.parks.models import Company

        company = Company.objects.create(name="Test Company", description="Original")

        content_type = ContentType.objects.get_for_model(company)
        submission = EditSubmission.objects.create(
            user=self.regular_user,
            content_type=content_type,
            object_id=company.id,
            submission_type="EDIT",
            changes={"name": "Spam Content"},
            status="PENDING",
            reason="Name change request",
        )

        # Moderator claims and then rejects
        submission.transition_to_claimed(user=self.moderator)
        submission.save()
        
        submission.refresh_from_db()
        self.assertEqual(submission.status, "CLAIMED")
        
        submission.transition_to_rejected(user=self.moderator)
        submission.handled_by = self.moderator
        submission.handled_at = timezone.now()
        submission.notes = "Rejected: Content appears to be spam"
        submission.save()

        submission.refresh_from_db()
        self.assertEqual(submission.status, "REJECTED")
        self.assertIn("spam", submission.notes.lower())


class SubmissionEscalationWorkflowTests(TestCase):
    """Tests for the submission escalation workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.regular_user = User.objects.create_user(
            username="user_esc", email="user_esc@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="mod_esc", email="mod_esc@example.com", password="testpass123", role="MODERATOR"
        )
        cls.admin = User.objects.create_user(
            username="admin_esc", email="admin_esc@example.com", password="testpass123", role="ADMIN"
        )

    def test_escalation_workflow(self):
        """
        Test complete escalation workflow.

        Flow: User submits → Moderator escalates → Admin reviews → Admin approves
        """
        from apps.moderation.models import EditSubmission
        from apps.parks.models import Company

        company = Company.objects.create(name="Sensitive Company", description="Original")

        content_type = ContentType.objects.get_for_model(company)
        submission = EditSubmission.objects.create(
            user=self.regular_user,
            content_type=content_type,
            object_id=company.id,
            submission_type="EDIT",
            changes={"name": "New Sensitive Name"},
            status="PENDING",
            reason="Major name change",
        )

        # Moderator claims and then escalates
        submission.transition_to_claimed(user=self.moderator)
        submission.save()
        
        submission.refresh_from_db()
        self.assertEqual(submission.status, "CLAIMED")
        
        submission.transition_to_escalated(user=self.moderator)
        submission.notes = "Escalated: Major change needs admin review"
        submission.save()

        self.assertEqual(submission.status, "ESCALATED")

        # Admin approves
        submission.transition_to_approved(user=self.admin)
        submission.handled_by = self.admin
        submission.handled_at = timezone.now()
        submission.save()

        submission.refresh_from_db()
        self.assertEqual(submission.status, "APPROVED")
        self.assertEqual(submission.handled_by, self.admin)


class ReportHandlingWorkflowTests(TestCase):
    """Tests for the moderation report handling workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.reporter = User.objects.create_user(
            username="reporter", email="reporter@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="mod_report", email="mod_report@example.com", password="testpass123", role="MODERATOR"
        )

    def test_report_resolution_workflow(self):
        """
        Test complete report resolution workflow.

        Flow: User reports → Moderator assigned → Moderator investigates → Resolved
        """
        from apps.moderation.models import ModerationReport
        from apps.parks.models import Company

        reported_company = Company.objects.create(name="Problematic Company", description="Some inappropriate content")

        content_type = ContentType.objects.get_for_model(reported_company)

        # User reports content
        report = ModerationReport.objects.create(
            report_type="CONTENT",
            status="PENDING",
            priority="HIGH",
            reported_entity_type="company",
            reported_entity_id=reported_company.id,
            content_type=content_type,
            reason="INAPPROPRIATE",
            description="This content is inappropriate",
            reported_by=self.reporter,
        )

        self.assertEqual(report.status, "PENDING")

        # Moderator claims and starts review
        report.transition_to_under_review(user=self.moderator)
        report.assigned_moderator = self.moderator
        report.save()

        self.assertEqual(report.status, "UNDER_REVIEW")
        self.assertEqual(report.assigned_moderator, self.moderator)

        # Moderator resolves
        report.transition_to_resolved(user=self.moderator)
        report.resolution_action = "CONTENT_REMOVED"
        report.resolution_notes = "Content was removed"
        report.resolved_at = timezone.now()
        report.save()

        report.refresh_from_db()
        self.assertEqual(report.status, "RESOLVED")
        self.assertIsNotNone(report.resolved_at)

    def test_report_dismissal_workflow(self):
        """
        Test report dismissal workflow for invalid reports.

        Flow: User reports → Moderator reviews → Moderator dismisses
        """
        from apps.moderation.models import ModerationReport
        from apps.parks.models import Company

        company = Company.objects.create(name="Valid Company", description="Normal content")

        content_type = ContentType.objects.get_for_model(company)

        report = ModerationReport.objects.create(
            report_type="CONTENT",
            status="PENDING",
            priority="LOW",
            reported_entity_type="company",
            reported_entity_id=company.id,
            content_type=content_type,
            reason="OTHER",
            description="I just do not like this",
            reported_by=self.reporter,
        )

        # Moderator claims
        report.transition_to_under_review(user=self.moderator)
        report.assigned_moderator = self.moderator
        report.save()

        # Moderator dismisses as invalid
        report.transition_to_dismissed(user=self.moderator)
        report.resolution_notes = "Report does not violate any guidelines"
        report.resolved_at = timezone.now()
        report.save()

        report.refresh_from_db()
        self.assertEqual(report.status, "DISMISSED")


class BulkOperationWorkflowTests(TestCase):
    """Tests for bulk operation workflows."""

    @classmethod
    def setUpTestData(cls):
        cls.admin = User.objects.create_user(
            username="admin_bulk", email="admin_bulk@example.com", password="testpass123", role="ADMIN"
        )

    def test_bulk_operation_success_workflow(self):
        """
        Test successful bulk operation workflow.

        Flow: Admin creates → Operation runs → Progress tracked → Completed
        """
        from apps.moderation.models import BulkOperation

        operation = BulkOperation.objects.create(
            operation_type="APPROVE_SUBMISSIONS",
            status="PENDING",
            total_items=10,
            processed_items=0,
            created_by=self.admin,
            parameters={"submission_ids": list(range(1, 11))},
        )

        self.assertEqual(operation.status, "PENDING")

        # Start operation
        operation.transition_to_running(user=self.admin)
        operation.started_at = timezone.now()
        operation.save()

        self.assertEqual(operation.status, "RUNNING")

        # Simulate progress
        for i in range(1, 11):
            operation.processed_items = i
            operation.save()

        # Complete operation
        operation.transition_to_completed(user=self.admin)
        operation.completed_at = timezone.now()
        operation.results = {"approved": 10, "failed": 0}
        operation.save()

        operation.refresh_from_db()
        self.assertEqual(operation.status, "COMPLETED")
        self.assertEqual(operation.processed_items, 10)

    def test_bulk_operation_failure_workflow(self):
        """
        Test bulk operation failure workflow.

        Flow: Admin creates → Operation runs → Error occurs → Failed
        """
        from apps.moderation.models import BulkOperation

        operation = BulkOperation.objects.create(
            operation_type="DELETE_CONTENT",
            status="PENDING",
            total_items=5,
            processed_items=0,
            created_by=self.admin,
            parameters={"content_ids": list(range(1, 6))},
        )

        operation.transition_to_running(user=self.admin)
        operation.started_at = timezone.now()
        operation.save()

        # Simulate partial progress then failure
        operation.processed_items = 2
        operation.failed_items = 3
        operation.transition_to_failed(user=self.admin)
        operation.completed_at = timezone.now()
        operation.results = {"error": "Database connection lost", "processed": 2}
        operation.save()

        operation.refresh_from_db()
        self.assertEqual(operation.status, "FAILED")
        self.assertEqual(operation.failed_items, 3)

    def test_bulk_operation_cancellation_workflow(self):
        """
        Test bulk operation cancellation workflow.

        Flow: Admin creates → Operation runs → Admin cancels
        """
        from apps.moderation.models import BulkOperation

        operation = BulkOperation.objects.create(
            operation_type="BATCH_UPDATE",
            status="PENDING",
            total_items=100,
            processed_items=0,
            created_by=self.admin,
            parameters={"update_field": "status"},
            can_cancel=True,
        )

        operation.transition_to_running(user=self.admin)
        operation.save()

        # Partial progress
        operation.processed_items = 30
        operation.save()

        # Admin cancels
        operation.transition_to_cancelled(user=self.admin)
        operation.completed_at = timezone.now()
        operation.results = {"cancelled_at": 30, "reason": "User requested cancellation"}
        operation.save()

        operation.refresh_from_db()
        self.assertEqual(operation.status, "CANCELLED")
        self.assertEqual(operation.processed_items, 30)


class ModerationQueueWorkflowTests(TestCase):
    """Tests for moderation queue workflows."""

    @classmethod
    def setUpTestData(cls):
        cls.moderator = User.objects.create_user(
            username="mod_queue", email="mod_queue@example.com", password="testpass123", role="MODERATOR"
        )

    def test_queue_completion_workflow(self):
        """
        Test queue item completion workflow.

        Flow: Item created → Moderator claims → Work done → Completed
        """
        from apps.moderation.models import ModerationQueue

        queue_item = ModerationQueue.objects.create(
            item_type="SUBMISSION_REVIEW",
            status="PENDING",
            priority="MEDIUM",
            title="Review edit submission #123",
            description="Review and process edit submission",
            entity_type="edit_submission",
            entity_id=123,
        )

        self.assertEqual(queue_item.status, "PENDING")

        # Moderator claims
        queue_item.transition_to_in_progress(user=self.moderator)
        queue_item.assigned_to = self.moderator
        queue_item.assigned_at = timezone.now()
        queue_item.save()

        self.assertEqual(queue_item.status, "IN_PROGRESS")

        # Work completed
        queue_item.transition_to_completed(user=self.moderator)
        queue_item.completed_at = timezone.now()
        queue_item.save()

        queue_item.refresh_from_db()
        self.assertEqual(queue_item.status, "COMPLETED")
