from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework.test import APIClient

from shop_management.models.data.customer import Customer
from shop_management.models.data.product import Product
from shop_management.models.data.purchase import Purchase, PurchaseItem
from shop_management.models.data.sale import Sale, SaleItem
from shop_management.models.data.shop import Shop
from shop_management.models.data.shop_account import Account
from shop_management.models.data.supplier import Supplier
from shop_management.models.data.utils import Currency


class DashboardSummaryTests(TestCase):
    def setUp(self):
        User = get_user_model()
        self.user = User.objects.create_user(username="dashboard", password="x", is_staff=True, allowed_tabs=["dashboard"])
        self.other = User.objects.create_user(username="other-dashboard", password="x", is_staff=True)
        self.shop = Shop.objects.create(owner=self.user, name="Kabul")
        self.other_shop = Shop.objects.create(owner=self.other, name="Hidden")
        self.currency = Currency.objects.create(shop=self.shop, title="AFN")
        other_currency = Currency.objects.create(shop=self.other_shop, title="USD")
        self.product = Product.objects.create(shop=self.shop, name="Vaccine")
        customer = Customer.objects.create(shop=self.shop, name="Customer", opening_balance=100, opening_balance_currency=self.currency)
        self.supplier = Supplier.objects.create(shop=self.shop, name="Supplier", opening_balance=80, opening_balance_currency=self.currency)
        Customer.objects.create(shop=self.other_shop, name="Hidden customer", opening_balance=999, opening_balance_currency=other_currency)
        sale = Sale.objects.create(shop=self.shop, customer=customer, currency=self.currency, document_status="POSTED", uses_inventory_engine=True)
        SaleItem.objects.create(sale=sale, product=self.product, quantity=2, sale_price=25)
        purchase = Purchase.objects.create(shop=self.shop, supplier=self.supplier, currency=self.currency, document_status="POSTED", uses_inventory_engine=True)
        PurchaseItem.objects.create(purchase=purchase, product=self.product, currency=self.currency, quantity=3, buy_price=10)
        self.client = APIClient()
        self.client.force_authenticate(self.user)

    def test_summary_uses_posted_data_and_enforces_branch_scope(self):
        response = self.client.get("/api/shop/dashboard-summary/", HTTP_X_SELECTED_SHOP=str(self.shop.pk), HTTP_HOST="localhost")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data["today_sales"], [{"currency": "AFN", "amount": "50.00"}])
        self.assertEqual(response.data["today_purchases"], [{"currency": "AFN", "amount": "30.00"}])
        self.assertEqual(response.data["receivables"], [{"currency": "AFN", "amount": "150.00"}])
        self.assertEqual(response.data["payables"], [{"currency": "AFN", "amount": "110.00"}])
        self.assertEqual([row["branch"] for row in response.data["branch_comparison"]], ["Kabul"])

    def test_supplier_payables_exclude_draft_and_cancelled_purchases(self):
        for document_status in (
            Purchase.DocumentStatus.DRAFT,
            Purchase.DocumentStatus.VOID,
        ):
            purchase = Purchase.objects.create(
                shop=self.shop,
                supplier=self.supplier,
                currency=self.currency,
                document_status=document_status,
                uses_inventory_engine=True,
            )
            PurchaseItem.objects.create(
                purchase=purchase,
                product=self.product,
                currency=self.currency,
                quantity=100,
                buy_price=10,
            )

        response = self.client.get(
            "/api/shop/dashboard-summary/",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_HOST="localhost",
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data["payables"], [
            {"currency": "AFN", "amount": "110.00"}
        ])
        self.assertEqual(response.data["today_purchases"], [
            {"currency": "AFN", "amount": "30.00"}
        ])

    def test_internal_clearing_accounts_are_excluded_from_operational_balances(self):
        Account.objects.create(
            shop=self.shop,
            name="Sale AFN Clearing",
            currency=self.currency,
            account_type="CASH",
            opening_balance="-3300",
            is_system_account=True,
        )
        cash = Account.objects.create(
            shop=self.shop,
            name="Kabul Cash",
            currency=self.currency,
            account_type="CASH",
            opening_balance="500",
        )

        response = self.client.get(
            "/api/shop/dashboard-summary/",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_HOST="localhost",
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual([row["id"] for row in response.data["account_balances"]], [cash.id])
        self.assertEqual(response.data["branch_comparison"][0]["account_balances"], [
            {"currency": "AFN", "amount": "500.00"}
        ])

    def test_forged_branch_is_forbidden(self):
        response = self.client.get(f"/api/shop/dashboard-summary/?shop={self.other_shop.pk}", HTTP_X_SELECTED_SHOP=str(self.shop.pk), HTTP_HOST="localhost")
        self.assertEqual(response.status_code, 403)

    def test_super_admin_can_compare_all_branches_despite_selected_branch_header(self):
        User = get_user_model()
        admin = User.objects.create_superuser(username="admin-overview", password="x")
        self.client.force_authenticate(admin)
        response = self.client.get(
            "/api/shop/dashboard-summary/",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_HOST="localhost",
        )
        self.assertEqual(response.status_code, 200)
        rows = {row["branch"]: row for row in response.data["branch_comparison"]}
        self.assertEqual(set(rows), {"Kabul", "Hidden"})
        self.assertEqual(rows["Kabul"]["receivables"], [{"currency": "AFN", "amount": "150.00"}])
        self.assertIn("stock_units", rows["Kabul"])

    def test_super_admin_branch_workspace_is_limited_to_selected_branch(self):
        User = get_user_model()
        admin = User.objects.create_superuser(username="admin-branch-workspace", password="x")
        self.client.force_authenticate(admin)
        response = self.client.get(
            "/api/shop/dashboard-summary/",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_X_ADMIN_BRANCH_CONTEXT="1",
            HTTP_HOST="localhost",
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual([row["branch"] for row in response.data["branch_comparison"]], ["Kabul"])

        customers = self.client.get(
            "/api/shop/customers/",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_X_ADMIN_BRANCH_CONTEXT="1",
            HTTP_HOST="localhost",
        )
        self.assertEqual(customers.status_code, 200)
        rows = customers.data.get("results", customers.data)
        self.assertEqual([row["name"] for row in rows], ["Customer"])

        currencies = self.client.get(
            "/api/shop/currencies/?page_size=all",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_X_ADMIN_BRANCH_CONTEXT="1",
            HTTP_HOST="localhost",
        )
        self.assertEqual(currencies.status_code, 200)
        rows = currencies.data.get("results", currencies.data)
        self.assertEqual([row["title"] for row in rows], ["AFN"])

    def test_super_admin_can_drill_into_a_branch_other_than_selected_header(self):
        User = get_user_model()
        admin = User.objects.create_superuser(username="admin-drilldown", password="x")
        self.client.force_authenticate(admin)
        response = self.client.get(
            f"/api/shop/dashboard-summary/?shop={self.other_shop.pk}",
            HTTP_X_SELECTED_SHOP=str(self.shop.pk),
            HTTP_HOST="localhost",
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual([row["branch"] for row in response.data["branch_comparison"]], ["Hidden"])
