import uuid
from django.contrib.auth.models import Permission
from django.test import TestCase, Client
from django.urls import reverse
from apps.service import test_repair as repair
from .test_usage import UsageFixture, setup_usage
from . import services as stock
from .models import PartsIssue, PartsDisposition, DefectiveRecovery


class UsageAdminTests(UsageFixture, TestCase):
    @classmethod
    def setUpTestData(cls):
        setup_usage(cls)
        cls.engineer.is_staff = True
        cls.engineer.save()
        cls.engineer.user_permissions.set(Permission.objects.filter(content_type__app_label="inventory"))

    def setUp(self):
        self.client.force_login(self.actor)

    def test_issue_admin_service_and_stale_form(self):
        self.receive()
        reservation = self.reserve(self.approve(self.request()))
        url = reverse("admin:inventory_partsissue_add")
        response = self.client.get(url)
        token = response.context["adminform"].form.initial["revisions"]
        data = {"reservation": str(reservation.pk), "note": "Issue", "revisions": token, "_save": "Save"}
        self.assertEqual(self.client.post(url, data).status_code, 302)
        self.client.post(url, data)
        self.assertEqual(PartsIssue.objects.count(), 1)

    def test_return_admin_delegates_and_rejects_stale_remaining_stock(self):
        issue = self.prepared_issue()
        url = reverse("admin:inventory_partsdisposition_add")
        response = self.client.get(url)
        token = response.context["adminform"].form.initial["revisions"]
        data = {"issue": str(issue.pk), "kind": "RETURNED", "quantity": "1", "destination": str(self.location.pk),
            "command_key": str(uuid.uuid4()), "revisions": token, "note": "Unused", "_save": "Save"}
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, 302)
        self.client.post(url, data | {"command_key": str(uuid.uuid4())})
        self.assertEqual(PartsDisposition.objects.count(), 1)

    def test_consume_admin_as_responsible_engineer(self):
        issue = self.prepared_issue()
        _, action = repair.prepared(self)
        self.client.force_login(self.engineer)
        url = reverse("admin:inventory_partsdisposition_add")
        response = self.client.get(url)
        token = response.context["adminform"].form.initial["revisions"]
        response = self.client.post(url, {"issue": str(issue.pk), "kind": "CONSUMED", "quantity": "1", "repair_action": str(action.pk),
            "command_key": str(uuid.uuid4()), "revisions": token, "note": "Installed", "_save": "Save"})
        self.assertEqual(response.status_code, 302)
        self.assertEqual(PartsDisposition.objects.get().kind, "CONSUMED")

    def test_recovery_admin_keeps_removed_components_separate(self):
        _, action = repair.prepared(self)
        quarantine = stock.create_location(actor=self.actor, company=self.company, service_center=self.center, code="DEFECTIVE", name="Defective", location_type="DEFECTIVE")
        self.client.force_login(self.engineer)
        url = reverse("admin:inventory_defectiverecovery_add")
        response = self.client.get(url)
        token = response.context["adminform"].form.initial["revisions"]
        response = self.client.post(url, {"repair_action": str(action.pk), "location": str(quarantine.pk), "component_description": "Removed screen",
            "quantity": "1", "command_key": str(uuid.uuid4()), "revisions": token, "note": "Cracked", "_save": "Save"})
        self.assertEqual(response.status_code, 302)
        self.assertEqual(DefectiveRecovery.objects.get().device, self.device)

    def test_history_is_readonly_and_undeletable(self):
        issue = self.prepared_issue()
        row = self.return_unused(issue)
        for name, obj in (("partsissue", issue), ("partsdisposition", row)):
            self.assertEqual(self.client.post(reverse(f"admin:inventory_{name}_change", args=[obj.pk]), {"note": "Rewrite"}).status_code, 403)
            self.assertEqual(self.client.post(reverse(f"admin:inventory_{name}_delete", args=[obj.pk]), {"post": "yes"}).status_code, 403)

    def test_usage_forms_require_csrf(self):
        client = Client(enforce_csrf_checks=True)
        client.force_login(self.actor)
        for name in ("partsissue", "partsdisposition", "defectiverecovery"):
            self.assertEqual(client.post(reverse(f"admin:inventory_{name}_add"), {}).status_code, 403)

    def test_generic_movement_form_still_requires_destination(self):
        response = self.client.get(reverse("admin:inventory_stockmovement_add"))
        self.assertTrue(response.context["adminform"].form.fields["destination"].required)
