from datetime import timedelta
from decimal import Decimal

from django.contrib.auth import get_user_model
from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import timezone

from billing.models import Payment, Renewal
from clients.models import Client, ClientPortalAccess
from core.choices import PaymentMethod, ServiceStatus, ServiceType
from services.models import Service

from .models import DatabaseCleanupOperation
from .services import execute_cleanup, preview_cleanup


@override_settings(
    K4W_DATABASE_MAINTENANCE_ENABLED=True,
    K4W_DATABASE_MAINTENANCE_ALLOW_FULL_RESET=True,
)
class DatabaseMaintenanceTests(TestCase):
    def setUp(self):
        User = get_user_model()
        self.admin = User.objects.create_superuser("root", "root@example.com", "Admin-Password-2026!")
        self.client_user = User.objects.create_user("cliente.teste", "cliente@example.com", "Client-Password-2026!")
        self.client_record = Client.objects.create(name="Cliente de teste", email="cliente@example.com")
        ClientPortalAccess.objects.create(client=self.client_record, user=self.client_user)
        self.service = Service.objects.create(
            client=self.client_record,
            service_type=ServiceType.HOSTING,
            name="Alojamento de teste",
            status=ServiceStatus.ACTIVE,
            next_renewal_date=timezone.localdate() + timedelta(days=30),
            cost_price=Decimal("20.00"),
            sale_price=Decimal("50.00"),
        )
        self.renewal = Renewal.objects.create(
            service=self.service,
            due_date=self.service.next_renewal_date,
            sale_amount=Decimal("50.00"),
        )
        Payment.objects.create(
            renewal=self.renewal,
            amount=Decimal("50.00"),
            method=PaymentMethod.BANK_TRANSFER,
        )

    def test_center_is_superuser_only(self):
        self.client.force_login(self.client_user)
        response = self.client.get(reverse("database_maintenance_center"))
        self.assertEqual(response.status_code, 302)
        self.client.force_login(self.admin)
        response = self.client.get(reverse("database_maintenance_center"))
        self.assertEqual(response.status_code, 200)

    def test_client_selection_expands_dependencies(self):
        preview = preview_cleanup(["clients"], self.admin, {"create_backup": False})
        self.assertIn("services", preview["effective_groups"])
        self.assertIn("billing", preview["effective_groups"])
        self.assertIn("client_accounts", preview["effective_groups"])
        self.assertGreaterEqual(preview["total_records"], 5)

    def test_selective_cleanup_preserves_current_admin(self):
        preview = preview_cleanup(["clients"], self.admin, {"create_backup": False, "delete_files": False})
        operation = DatabaseCleanupOperation.objects.create(
            mode=DatabaseCleanupOperation.Mode.SELECTIVE,
            requested_by=self.admin,
            selected_groups=preview["selected_groups"],
            effective_groups=preview["effective_groups"],
            options={"create_backup": False, "delete_files": False},
            preview=preview,
        )
        result = execute_cleanup(operation, self.admin)
        self.assertGreater(result["total_deleted"], 0)
        self.assertTrue(get_user_model().objects.filter(pk=self.admin.pk).exists())
        self.assertFalse(get_user_model().objects.filter(pk=self.client_user.pk).exists())
        self.assertEqual(Client.objects.count(), 0)
        self.assertEqual(Service.objects.count(), 0)
        self.assertEqual(Renewal.objects.count(), 0)
        self.assertEqual(Payment.objects.count(), 0)

    def test_confirmation_requires_exact_phrase_and_password(self):
        self.client.force_login(self.admin)
        response = self.client.post(
            reverse("database_maintenance_center"),
            {
                "mode": "selective",
                "groups": ["billing"],
                "create_backup": "",
            },
        )
        self.assertEqual(response.status_code, 302)
        operation = DatabaseCleanupOperation.objects.latest("created_at")
        response = self.client.post(
            reverse("database_maintenance_confirm", args=[operation.pk]),
            {
                "confirmation": "ERRADO",
                "password": "Admin-Password-2026!",
                "acknowledge": "on",
            },
        )
        self.assertEqual(response.status_code, 200)
        operation.refresh_from_db()
        self.assertEqual(operation.status, DatabaseCleanupOperation.Status.PREVIEWED)

        response = self.client.post(
            reverse("database_maintenance_confirm", args=[operation.pk]),
            {
                "confirmation": "ELIMINAR SELECIONADOS",
                "password": "Admin-Password-2026!",
                "acknowledge": "on",
            },
        )
        self.assertEqual(response.status_code, 302)
        operation.refresh_from_db()
        self.assertEqual(operation.status, DatabaseCleanupOperation.Status.COMPLETED)
