"""
Inventory Module — API Integration Tests.
تست‌های یکپارچه API ماژول انبار و موجودی.
"""
import uuid
from datetime import date
from decimal import Decimal

import pytest

pytestmark = pytest.mark.django_db

BASE = "/api/v1/inventory"


# ═══════════════════════════════════════════════════════════════
# ITEM TYPE
# ═══════════════════════════════════════════════════════════════


class TestItemTypeAPI:
    URL = f"{BASE}/item-types/"

    def test_list(self, admin_client, item_type):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client):
        data = {"type_code": "FIN", "type_name": "محصول نهایی", "is_active": True}
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201
        assert res.data["type_code"] == "FIN"

    def test_retrieve(self, admin_client, item_type):
        res = admin_client.get(f"{self.URL}{item_type.pk}/")
        assert res.status_code == 200
        assert res.data["type_code"] == "RAW"

    def test_update(self, admin_client, item_type):
        res = admin_client.patch(
            f"{self.URL}{item_type.pk}/",
            {"type_name": "ماده اولیه ویرایش‌شده"},
            format="json",
        )
        assert res.status_code == 200

    def test_delete(self, admin_client, item_type):
        res = admin_client.delete(f"{self.URL}{item_type.pk}/")
        assert res.status_code in (204, 200)

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ITEM GROUP
# ═══════════════════════════════════════════════════════════════


class TestItemGroupAPI:
    URL = f"{BASE}/item-groups/"

    def test_list(self, admin_client, item_group):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, costing_method):
        data = {
            "group_code": "ELC",
            "group_name": "الکترونیک",
            "default_costing_method": str(costing_method.pk),
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, item_group):
        res = admin_client.get(f"{self.URL}{item_group.pk}/")
        assert res.status_code == 200

    def test_update(self, admin_client, item_group):
        res = admin_client.patch(
            f"{self.URL}{item_group.pk}/",
            {"group_name": "مواد ویرایش‌شده"},
            format="json",
        )
        assert res.status_code == 200

    def test_delete(self, admin_client, item_group):
        res = admin_client.delete(f"{self.URL}{item_group.pk}/")
        assert res.status_code in (204, 200)

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# UNIT OF MEASURE
# ═══════════════════════════════════════════════════════════════


class TestUnitOfMeasureAPI:
    URL = f"{BASE}/uom/"

    def test_list(self, admin_client, uom):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client):
        data = {
            "uom_code": "MTR",
            "uom_name": "Meter",
            "uom_name_local": "متر",
            "uom_type": "LENGTH",
            "decimal_places": 2,
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, uom):
        res = admin_client.get(f"{self.URL}{uom.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ITEM
# ═══════════════════════════════════════════════════════════════


class TestItemAPI:
    URL = f"{BASE}/items/"

    def test_list(self, admin_client, item):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item_type, item_group, uom):
        data = {
            "item_code": "MAT-002",
            "item_name": "Copper Wire",
            "item_name_local": "سیم مسی",
            "item_type": str(item_type.pk),
            "item_group": str(item_group.pk),
            "base_uom": str(uom.pk),
            "is_batch_managed": False,
            "is_serial_managed": False,
            "is_purchasable": True,
            "is_saleable": True,
            "is_stockable": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201
        assert res.data["item_code"] == "MAT-002"

    def test_retrieve(self, admin_client, item):
        res = admin_client.get(f"{self.URL}{item.pk}/")
        assert res.status_code == 200

    def test_update(self, admin_client, item):
        res = admin_client.patch(
            f"{self.URL}{item.pk}/",
            {"item_name_local": "میلگرد ویرایش‌شده"},
            format="json",
        )
        assert res.status_code == 200

    def test_delete(self, admin_client, item):
        res = admin_client.delete(f"{self.URL}{item.pk}/")
        assert res.status_code in (204, 200)

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ITEM ATTRIBUTE
# ═══════════════════════════════════════════════════════════════


class TestItemAttributeAPI:
    URL = f"{BASE}/item-attributes/"

    def test_list(self, admin_client, item_attribute):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item):
        data = {
            "item": str(item.pk),
            "attribute_name": "رنگ",
            "attribute_value": "نقره‌ای",
            "attribute_data_type": "Text",
            "display_order": 2,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ITEM UOM
# ═══════════════════════════════════════════════════════════════


class TestItemUOMAPI:
    URL = f"{BASE}/item-uom/"

    def test_list(self, admin_client, item_uom):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item, uom_piece):
        data = {
            "item": str(item.pk),
            "uom": str(uom_piece.pk),
            "conversion_factor": "10.0",
            "is_base_uom": False,
            "is_purchase_uom": True,
            "is_sales_uom": False,
            "is_stock_uom": False,
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# WAREHOUSE
# ═══════════════════════════════════════════════════════════════


class TestWarehouseAPI:
    URL = f"{BASE}/warehouses/"

    def test_list(self, admin_client, warehouse):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client):
        data = {
            "warehouse_code": "WH-02",
            "warehouse_name": "انبار فرعی",
            "warehouse_type": "PHYSICAL",
            "city": "اصفهان",
            "is_negative_stock_allowed": False,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201
        assert res.data["warehouse_code"] == "WH-02"

    def test_retrieve(self, admin_client, warehouse):
        res = admin_client.get(f"{self.URL}{warehouse.pk}/")
        assert res.status_code == 200

    def test_update(self, admin_client, warehouse):
        res = admin_client.patch(
            f"{self.URL}{warehouse.pk}/",
            {"warehouse_name": "انبار مرکزی ویرایش‌شده"},
            format="json",
        )
        assert res.status_code == 200

    def test_delete(self, admin_client, warehouse):
        res = admin_client.delete(f"{self.URL}{warehouse.pk}/")
        assert res.status_code in (204, 200)

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# STORAGE LOCATION
# ═══════════════════════════════════════════════════════════════


class TestStorageLocationAPI:
    URL = f"{BASE}/storage-locations/"

    def test_list(self, admin_client, storage_location):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, warehouse):
        data = {
            "location_code": "B-02-01",
            "location_name": "ناحیه B",
            "warehouse": str(warehouse.pk),
            "location_type": "ZONE",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ITEM WAREHOUSE
# ═══════════════════════════════════════════════════════════════


class TestItemWarehouseAPI:
    URL = f"{BASE}/item-warehouses/"

    def test_list(self, admin_client, item_warehouse):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item, warehouse_transit):
        data = {
            "item": str(item.pk),
            "warehouse": str(warehouse_transit.pk),
            "reorder_point": "200.0000",
            "safety_stock": "50.0000",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# STOCK STATUS
# ═══════════════════════════════════════════════════════════════


class TestStockStatusAPI:
    URL = f"{BASE}/stock-statuses/"

    def test_list(self, admin_client, stock_status):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client):
        data = {
            "status_code": "QI",
            "status_name": "در بازرسی",
            "status_type": "QUALITY_INSPECTION",
            "is_available_for_sales": False,
            "is_available_for_production": False,
            "sort_order": 3,
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, stock_status):
        res = admin_client.get(f"{self.URL}{stock_status.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# STOCK LEDGER
# ═══════════════════════════════════════════════════════════════


class TestStockLedgerAPI:
    URL = f"{BASE}/stock-ledger/"

    def test_list(self, admin_client, stock_ledger_entry):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_retrieve(self, admin_client, stock_ledger_entry):
        res = admin_client.get(f"{self.URL}{stock_ledger_entry.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# STOCK BALANCE
# ═══════════════════════════════════════════════════════════════


class TestStockBalanceAPI:
    URL = f"{BASE}/stock-balance/"

    def test_list(self, admin_client, stock_balance):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_retrieve(self, admin_client, stock_balance):
        res = admin_client.get(f"{self.URL}{stock_balance.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# BATCH
# ═══════════════════════════════════════════════════════════════


class TestBatchAPI:
    URL = f"{BASE}/batches/"

    def test_list(self, admin_client, batch):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item):
        data = {
            "batch_number": "B-2024-002",
            "item": str(item.pk),
            "manufacturing_date": "2024-06-01",
            "expiry_date": "2025-06-01",
            "batch_status": "ACTIVE",
            "quality_status": "APPROVED",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, batch):
        res = admin_client.get(f"{self.URL}{batch.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# SERIAL NUMBER
# ═══════════════════════════════════════════════════════════════


class TestSerialNumberAPI:
    URL = f"{BASE}/serial-numbers/"

    def test_list(self, admin_client, serial_number):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item_serial_managed, warehouse):
        data = {
            "serial_no": "SN-2024-0002",
            "item": str(item_serial_managed.pk),
            "current_warehouse": str(warehouse.pk),
            "serial_status": "IN_STOCK",
            "quality_status": "APPROVED",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, serial_number):
        res = admin_client.get(f"{self.URL}{serial_number.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# COSTING METHOD
# ═══════════════════════════════════════════════════════════════


class TestCostingMethodAPI:
    URL = f"{BASE}/costing-methods/"

    def test_list(self, admin_client, costing_method):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client):
        data = {
            "method_code": "WAC",
            "method_name": "میانگین موزون",
            "description": "Weighted Average Cost",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, costing_method):
        res = admin_client.get(f"{self.URL}{costing_method.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ITEM COSTING
# ═══════════════════════════════════════════════════════════════


class TestItemCostingAPI:
    URL = f"{BASE}/item-costing/"

    def test_list(self, admin_client, item_costing):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item_serial_managed, costing_method):
        data = {
            "item": str(item_serial_managed.pk),
            "costing_method": str(costing_method.pk),
            "standard_cost": "150000.0000",
            "currency_code": "IRR",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# RESERVATION
# ═══════════════════════════════════════════════════════════════


class TestReservationAPI:
    URL = f"{BASE}/reservations/"

    def test_list(self, admin_client, reservation):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item, warehouse, uom):
        data = {
            "reservation_date": "2024-05-01",
            "item": str(item.pk),
            "warehouse": str(warehouse.pk),
            "reserved_quantity": "200.0000",
            "uom": str(uom.pk),
            "source_document_type": "PRODUCTION_ORDER",
            "priority_level": 5,
            "reservation_status": "ACTIVE",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, reservation):
        res = admin_client.get(f"{self.URL}{reservation.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# ALLOCATION
# ═══════════════════════════════════════════════════════════════


class TestAllocationAPI:
    URL = f"{BASE}/allocations/"

    def test_list(self, admin_client, allocation):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item, warehouse, uom, reservation):
        data = {
            "allocation_date": "2024-05-05",
            "reservation": str(reservation.pk),
            "item": str(item.pk),
            "warehouse": str(warehouse.pk),
            "allocated_quantity": "50.0000",
            "uom": str(uom.pk),
            "allocation_status": "ALLOCATED",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# PHYSICAL INVENTORY
# ═══════════════════════════════════════════════════════════════


class TestPhysicalInventoryAPI:
    URL = f"{BASE}/physical-inventories/"

    def test_list(self, admin_client, physical_inventory):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, warehouse):
        data = {
            "inventory_date": "2024-06-01",
            "inventory_type": "FULL",
            "warehouse": str(warehouse.pk),
            "inventory_status": "DRAFT",
            "is_blind_count": False,
            "is_stock_frozen": False,
            "variance_threshold_percent": "5.00",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, physical_inventory):
        res = admin_client.get(f"{self.URL}{physical_inventory.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# PHYSICAL INVENTORY LINE
# ═══════════════════════════════════════════════════════════════


class TestPhysicalInventoryLineAPI:
    URL = f"{BASE}/physical-inventory-lines/"

    def test_list(self, admin_client, physical_inventory_line):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, physical_inventory, item, warehouse, uom):
        data = {
            "physical_inventory": str(physical_inventory.pk),
            "line_number": 2,
            "item": str(item.pk),
            "warehouse": str(warehouse.pk),
            "book_quantity": "500.0000",
            "uom": str(uom.pk),
            "line_status": "PENDING",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# CYCLE COUNT SCHEDULE
# ═══════════════════════════════════════════════════════════════


class TestCycleCountScheduleAPI:
    URL = f"{BASE}/cycle-count-schedules/"

    def test_list(self, admin_client, cycle_count_schedule):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, warehouse):
        data = {
            "schedule_name": "شمارش هفتگی B",
            "warehouse": str(warehouse.pk),
            "count_frequency_days": 7,
            "abc_class": "B",
            "next_count_date": "2024-04-08",
            "is_active": True,
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# INSPECTION LOT
# ═══════════════════════════════════════════════════════════════


class TestInspectionLotAPI:
    URL = f"{BASE}/inspection-lots/"

    def test_list(self, admin_client, inspection_lot):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, item, warehouse, uom):
        data = {
            "inspection_type": "INCOMING",
            "inspection_date": "2024-06-15",
            "item": str(item.pk),
            "warehouse": str(warehouse.pk),
            "inspection_quantity": "200.0000",
            "sample_size": "20.0000",
            "uom": str(uom.pk),
            "inspection_status": "PENDING",
            "quality_decision": "PENDING",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_retrieve(self, admin_client, inspection_lot):
        res = admin_client.get(f"{self.URL}{inspection_lot.pk}/")
        assert res.status_code == 200

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# INSPECTION RESULT
# ═══════════════════════════════════════════════════════════════


class TestInspectionResultAPI:
    URL = f"{BASE}/inspection-results/"

    def test_list(self, admin_client, inspection_result):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, inspection_lot):
        data = {
            "inspection_lot": str(inspection_lot.pk),
            "inspection_characteristic": "وزن",
            "target_value": "50.00",
            "actual_value": "50.10",
            "tolerance_lower": "49.50",
            "tolerance_upper": "50.50",
            "result_status": "PASS",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401


# ═══════════════════════════════════════════════════════════════
# QUALITY ACTION
# ═══════════════════════════════════════════════════════════════


class TestQualityActionAPI:
    URL = f"{BASE}/quality-actions/"

    def test_list(self, admin_client, quality_action):
        res = admin_client.get(self.URL)
        assert res.status_code == 200

    def test_create(self, admin_client, inspection_lot):
        data = {
            "inspection_lot": str(inspection_lot.pk),
            "action_type": "QUARANTINE",
            "action_date": "2024-06-16",
            "action_quantity": "50.0000",
        }
        res = admin_client.post(self.URL, data, format="json")
        assert res.status_code == 201

    def test_unauthenticated(self, api_client):
        res = api_client.get(self.URL)
        assert res.status_code == 401
