"""Forged and stale commercial Admin requests across domain boundaries."""
import uuid
from django.contrib.auth import get_user_model
from django.test import TestCase, Client
from django.urls import reverse
from apps.commercial.test_payment import PaymentFixture, shared_payment_data
from apps.commercial.test_invoice import InvoiceFixture
from apps.commercial import models as m
from apps.inventory.test_usage import setup_usage
from apps.service import test_handover as delivery
from apps.service.test_handover_admin import form_data
from apps.service.models import ServiceCaseHandover


class PaymentAdminAudit(PaymentFixture, TestCase):
    @classmethod
    def setUpTestData(cls):
        shared_payment_data(cls)

    def setUp(self):
        self.client.force_login(self.actor)

    def url(self):
        return reverse("admin:commercial_invoice_settlement", args=[self.invoice.pk])

    def token(self):
        return self.client.get(self.url()).context_data["revision_token"]

    def test_stale_paid_handover_form_rechecks_reversed_payment(self):
        payment = self.pay()
        delivery.released(self)
        url = reverse("admin:service_servicecase_handover", args=[self.case.pk])
        token = self.client.get(url).context_data["form"].initial["revision"]
        self.reverse_payment(payment)
        response = self.client.post(url, form_data(self, "handover", token))
        self.assertContains(response, "Outstanding customer liability")
        self.assertFalse(ServiceCaseHandover.objects.exists())
        self.assertEqual(self.summary()["balance"], 100)

    def test_stale_due_release_after_payment_cannot_record_old_balance(self):
        token = self.token()
        self.pay(amount="20")
        response = self.client.post(self.url(), dict(operation="release", revision_token=token, reason="Synthetic approval"))
        self.assertEqual(response.status_code, 400)
        self.assertFalse(m.ServiceFinancialRelease.objects.exists())
        self.assertEqual(self.summary()["balance"], 80)

    def test_signed_form_cannot_be_transferred_between_actors(self):
        token = self.token()
        other = get_user_model().objects.create_superuser(username="audit-second-admin")
        self.client.force_login(other)
        self.assertEqual(self.client.post(self.url(), dict(operation="receive", revision_token=token, amount="1", method="CASH")).status_code, 400)
        self.assertFalse(m.ServicePayment.objects.exists())

    def test_get_operations_never_create_money_or_release(self):
        for operation in ("receive", "reverse", "release"):
            self.assertEqual(self.client.get(self.url(), dict(operation=operation, amount="100", method="CASH")).status_code, 200)
        self.assertFalse(m.ServicePayment.objects.exists())
        self.assertFalse(m.ServiceFinancialRelease.objects.exists())

    def test_forged_urls_and_posted_receipt_edit(self):
        self.assertEqual(self.client.get(reverse("admin:commercial_invoice_settlement", args=[uuid.uuid4()])).status_code, 404)
        payment = self.pay()
        url = reverse("admin:commercial_servicepaymentreceipt_change", args=[payment.receipt.pk])
        self.assertEqual(self.client.post(url, dict(amount="0.01", number="RCT-99999999", _save="Save")).status_code, 403)
        payment.receipt.refresh_from_db()
        self.assertEqual(payment.receipt.amount, 100)

    def test_csrf_on_reversal_and_due_release(self):
        payment = self.pay(amount="10")
        client = Client(enforce_csrf_checks=True)
        client.force_login(self.actor)
        for operation in ("reverse", "release"):
            self.assertEqual(client.post(self.url(), dict(operation=operation, revision_token=self.token(), payment=payment.pk, reason="Synthetic")).status_code, 403)
        self.assertFalse(m.PaymentReversal.objects.exists())
        self.assertFalse(m.ServiceFinancialRelease.objects.exists())


class QuotationInvoiceAdminAudit(InvoiceFixture, TestCase):
    @classmethod
    def setUpTestData(cls):
        setup_usage(cls)

    def setUp(self):
        self.client.force_login(self.actor)

    def test_stale_submit_and_obsolete_approval_forms(self):
        row = self.lines(self.create())
        url = reverse("admin:commercial_quotation_workflow", args=[row.pk])
        token = self.client.get(url).context_data["revision_token"]
        row = self.update(row)
        self.assertEqual(self.client.post(url, dict(operation="submit", revision_token=token)).status_code, 400)
        row = self.submit(row)
        token = self.client.get(url).context_data["revision_token"]
        replacement = self.revise(row)
        self.assertEqual(self.client.post(url, dict(operation="decision", revision_token=token, outcome="APPROVED", channel="PHONE", recipient_name="Synthetic", reference="Synthetic")).status_code, 400)
        self.assertFalse(m.QuotationDecision.objects.exists())
        self.assertEqual(replacement.status, "DRAFT")

    def test_quotation_replacement_invalidates_old_invoice_form(self):
        row = self.billed()
        url = reverse("admin:commercial_invoice_workflow", args=[row.pk])
        token = self.client.get(url).context_data["revision_token"]
        self.revise(self.quote)
        data = dict(operation="reconcile", revision_token=token)
        for prefix in ("allocations", "confirmations", "adjustments"):
            data.update({f"{prefix}-TOTAL_FORMS":"0", f"{prefix}-INITIAL_FORMS":"0"})
        self.assertEqual(self.client.post(url, data).status_code, 400)
        row.refresh_from_db()
        self.assertEqual((row.generation, row.grand_total), (1, 100))
