from io import BytesIO
from tempfile import TemporaryDirectory

from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, override_settings
from django.urls import reverse
from openpyxl import Workbook

from clients.models import Client
from services.models import Service
from .models import ImportBatch, ImportRow
from .services import analyse_batch


def demo_workbook_bytes():
    workbook = Workbook()
    hosting = workbook.active
    hosting.title = "Alojamentos"
    hosting.append(["DOMÍNIO", "Tipo", "Situação", "Expira", "Valor", "A cobrar"])
    hosting.append(["demo-hosting.pt", "A", "PAGO", "16/07/2027", 55, 90])
    hosting.append(["dois.pt e segundo.pt", "A", "PAGAR", "", 40, 75])

    domains = workbook.create_sheet("Domínios")
    domains.append(["Domínio", "Criação", "Expira", "Preço", "A cobrar"])
    domains.append(["demo-domain.pt", "01/01/2024", "01/01/2027", 12, 25])

    websites = workbook.create_sheet("Websites")
    websites.append(["Website", "Ano", "Valor contratado", "Recebido", "Tema"])
    websites.append(["site-demo.pt", 2025, 750, 500, "Tema próprio"])

    technical = workbook.create_sheet("dominios associados")
    technical.append(["Domínios adicionais", "Raiz do documento", "Subdomínio", "Base de dados", "Tamanho"])
    technical.append(["site-demo.pt", "/public_html/site-demo", "site-demo", "demo_db", "12 MB"])

    output = BytesIO()
    workbook.save(output)
    return output.getvalue()


class ImportPreviewTests(TestCase):
    def setUp(self):
        self.temp_media = TemporaryDirectory()
        self.addCleanup(self.temp_media.cleanup)
        self.override = override_settings(MEDIA_ROOT=self.temp_media.name)
        self.override.enable()
        self.addCleanup(self.override.disable)

    def create_batch(self):
        file = SimpleUploadedFile(
            "alojamentos_teste.xlsx",
            demo_workbook_bytes(),
            content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        )
        return ImportBatch.objects.create(title="Teste de importação", source_file=file)

    def test_analysis_creates_preview_without_business_records(self):
        batch = self.create_batch()
        analyse_batch(batch)
        batch.refresh_from_db()

        self.assertEqual(batch.status, ImportBatch.Status.REVIEW)
        self.assertEqual(batch.rows.count(), 5)
        self.assertGreater(batch.warning_rows, 0)
        self.assertEqual(Client.objects.count(), 0)
        self.assertEqual(Service.objects.count(), 0)
        self.assertTrue(batch.rows.filter(record_type=ImportRow.RecordType.DOMAIN).exists())
        self.assertTrue(batch.rows.filter(issues__isnull=False).exists())

    def test_multiple_domains_are_flagged(self):
        batch = self.create_batch()
        analyse_batch(batch)
        row = batch.rows.get(source_label="dois.pt e segundo.pt")
        self.assertEqual(row.severity, ImportRow.Severity.WARNING)
        self.assertTrue(any("vários domínios" in issue for issue in row.issues))


class ImportAdminTests(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.user = get_user_model().objects.create_superuser(
            "import-admin", "import@example.com", "test-password"
        )

    def setUp(self):
        self.client.force_login(self.user)

    def test_import_admin_pages_use_visual_system(self):
        for url_name in (
            "admin:imports_importbatch_changelist",
            "admin:imports_importrow_changelist",
            "admin:imports_importbatch_add",
        ):
            with self.subTest(url_name=url_name):
                response = self.client.get(reverse(url_name))
                self.assertEqual(response.status_code, 200)
                self.assertContains(response, "portal-")

from domains.models import Domain
from .models import ImportedObject
from .services import execute_batch, rollback_batch, simulate_batch


class ImportExecutionTests(ImportPreviewTests):
    def prepare_domain_batch(self):
        batch = self.create_batch()
        analyse_batch(batch)
        batch.rows.exclude(record_type=ImportRow.RecordType.DOMAIN).update(decision=ImportRow.Decision.IGNORE)
        domain_row = batch.rows.get(record_type=ImportRow.RecordType.DOMAIN)
        domain_row.decision = ImportRow.Decision.IMPORT
        domain_row.proposed_client_name = "Cliente Importado"
        domain_row.save(update_fields=["decision", "proposed_client_name", "updated_at"])
        batch.status = ImportBatch.Status.READY
        batch.save(update_fields=["status", "updated_at"])
        return batch, domain_row

    def test_simulation_does_not_create_business_records(self):
        batch, _ = self.prepare_domain_batch()
        summary = simulate_batch(batch)
        batch.refresh_from_db()
        self.assertEqual(summary["failed"], 0)
        self.assertEqual(batch.status, ImportBatch.Status.SIMULATED)
        self.assertEqual(Client.objects.count(), 0)
        self.assertEqual(Service.objects.count(), 0)

    def test_execute_and_rollback_import(self):
        batch, row = self.prepare_domain_batch()
        simulate_batch(batch)
        summary = execute_batch(batch)
        batch.refresh_from_db()
        row.refresh_from_db()
        self.assertEqual(batch.status, ImportBatch.Status.IMPORTED)
        self.assertGreater(summary["objects_created"], 0)
        self.assertEqual(row.processing_status, ImportRow.ProcessingStatus.CREATED)
        self.assertTrue(Domain.objects.filter(domain_name="demo-domain.pt").exists())
        self.assertTrue(ImportedObject.objects.filter(batch=batch, action=ImportedObject.Action.CREATED).exists())

        rollback = rollback_batch(batch)
        batch.refresh_from_db()
        self.assertGreater(rollback["deleted_objects"], 0)
        self.assertEqual(batch.status, ImportBatch.Status.ROLLED_BACK)
        self.assertFalse(Domain.objects.filter(domain_name="demo-domain.pt").exists())
