from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from rest_framework.test import APIClient

from shop_management.models.data.inventory import InventoryBatch, StockBalance, StockMovement
from shop_management.models.data.organization import Warehouse
from shop_management.models.data.product import Product
from shop_management.models.data.shop import Shop
from shop_management.models.data.stock_adjustment import StockAdjustment
from shop_management.models.data.utils import Currency


HEADER = "product_code,batch_number,manufacture_date,expiry_date,quantity,unit_cost,currency\n"


class OpeningInventoryTests(TestCase):
    def setUp(self):
        self.user = get_user_model().objects.create_user(
            username="opening-user", password="test", is_staff=True
        )
        self.user.allowed_tabs = ["stock"]
        self.user.save(update_fields=["allowed_tabs"])
        self.shop = Shop.objects.create(owner=self.user, name="Kabul")
        self.warehouse = Warehouse.objects.create(shop=self.shop, code="MAIN", name="Main")
        self.currency = Currency.objects.create(shop=self.shop, title="AFN")
        self.product = Product.objects.create(
            shop=self.shop, name="Medicine", code="MED-1",
            requires_batch=True, requires_expiry=True,
        )
        self.client = APIClient()
        self.client.force_authenticate(self.user)

    def upload(self, body, mode="preview"):
        file = SimpleUploadedFile("opening.csv", (HEADER + body).encode(), content_type="text/csv")
        return self.client.post(
            "/api/shop/opening-inventory/",
            {"warehouse": self.warehouse.id, "mode": mode, "reference": "Go-live count", "file": file},
            format="multipart",
        )

    def test_preview_validates_without_writing(self):
        response = self.upload("MED-1,B-1,2026-01-01,2027-01-01,10,25.5,AFN\n")
        self.assertEqual(response.status_code, 200, response.data)
        self.assertTrue(response.data["valid"])
        self.assertEqual(InventoryBatch.objects.count(), 0)
        self.assertEqual(StockBalance.objects.count(), 0)

    def test_post_creates_opening_document_balance_and_movement(self):
        response = self.upload(
            "MED-1,B-1,2026-01-01,2027-01-01,10,25.5,AFN\n", mode="post"
        )
        self.assertEqual(response.status_code, 200, response.data)
        adjustment = StockAdjustment.objects.get()
        self.assertEqual(adjustment.adjustment_kind, StockAdjustment.Kind.OPENING)
        self.assertEqual(adjustment.status, StockAdjustment.Status.POSTED)
        self.assertEqual(str(StockBalance.objects.get().quantity), "10.0000")
        self.assertEqual(StockMovement.objects.get().movement_type, StockMovement.MovementType.OPENING)

    def test_invalid_rows_create_nothing(self):
        response = self.upload("UNKNOWN,B-1,,,10,25.5,AFN\n", mode="post")
        self.assertEqual(response.status_code, 400)
        self.assertEqual(StockAdjustment.objects.count(), 0)
        self.assertEqual(InventoryBatch.objects.count(), 0)
        self.assertEqual(StockMovement.objects.count(), 0)

    def test_duplicate_product_batch_is_rejected(self):
        row = "MED-1,B-1,2026-01-01,2027-01-01,10,25.5,AFN\n"
        response = self.upload(row + row)
        self.assertEqual(response.status_code, 200)
        self.assertFalse(response.data["valid"])
        self.assertTrue(any("Duplicate" in message for error in response.data["errors"] for message in error["messages"]))

    def test_template_download(self):
        metadata = self.client.get(f"/api/shop/opening-inventory/?warehouse={self.warehouse.id}")
        self.assertEqual(metadata.status_code, 200)
        self.assertEqual(metadata.data["products"][0]["code"], "MED-1")
        response = self.client.get(f"/api/shop/opening-inventory/template/?warehouse={self.warehouse.id}")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "text/csv")
        self.assertIn(b"product_code", response.content)
        self.assertIn(b"MED-1", response.content)
        self.assertIn(b"requires_expiry", response.content)
