from decimal import Decimal
from datetime import date
from django.test import TestCase,Client
from django.contrib.auth.models import User
from django.urls import reverse
from .models import Branch,Profile,Category,Product,Stock,StockHistory,PurchaseRequest,RequestItem,Notification
from .jalali import to_jalali,jalali_to_gregorian

class SamshafWorkflowTests(TestCase):
    def setUp(self):
        self.a=Branch.objects.create(name='اندرزگو')
        self.b=Branch.objects.create(name='شهرک غرب')
        self.root=Category.objects.create(name='کاله',slug='kalleh')
        self.p=Product.objects.create(name='شیر',category=self.root,unit='باکس',minimum=1,estimated_price=100000)
        self.manager=User.objects.create_user('manager',password='strong-password-12')
        Profile.objects.create(user=self.manager,role='branch',branch=self.a)
        self.other=User.objects.create_user('other',password='strong-password-12')
        Profile.objects.create(user=self.other,role='branch',branch=self.b)
        self.buyer=User.objects.create_user('buyer',password='strong-password-12')
        Profile.objects.create(user=self.buyer,role='buyer')
        self.admin=User.objects.create_user('director',password='strong-password-12')
        Profile.objects.create(user=self.admin,role='admin')
    def test_jalali_roundtrip(self):
        self.assertEqual(to_jalali(date(2026,11,9)),(1405,8,18))
        self.assertEqual(jalali_to_gregorian(1405,8,18),date(2026,11,9))
    def test_manager_registers_stock_and_request(self):
        self.client.force_login(self.manager)
        r=self.client.post(reverse('inventory'),{'branch':str(self.b.pk),'category':str(self.root.pk),f'stock_{self.p.pk}':'2',f'buy_{self.p.pk}':'5','note':'برای این هفته'})
        self.assertEqual(r.status_code,302)
        self.assertEqual(Stock.objects.get(branch=self.a,product=self.p).quantity,Decimal('2'))
        self.assertFalse(Stock.objects.filter(branch=self.b).exists())
        order=PurchaseRequest.objects.get()
        item=order.items.get()
        self.assertEqual(item.price_snapshot,Decimal(100000))
        self.assertEqual(order.estimated_total,Decimal(500000))
        self.assertTrue(Notification.objects.filter(recipient=self.buyer).exists())
    def test_prices_snapshot_dont_change_after_edit(self):
        o=PurchaseRequest.objects.create(branch=self.a,category=self.root,requested_by=self.manager)
        RequestItem.objects.create(request=o,product=self.p,quantity=2,unit_snapshot='باکس',price_snapshot=100000)
        self.p.estimated_price=150000;self.p.save()
        self.assertEqual(o.estimated_total,200000)
    def test_branch_cannot_read_another_branch_order(self):
        o=PurchaseRequest.objects.create(branch=self.b,category=self.root,requested_by=self.other)
        self.client.force_login(self.manager)
        response=self.client.get(reverse('order_detail',args=[o.pk]))
        self.assertEqual(response.status_code,404)
        self.assertEqual(self.client.post(reverse('approve_order',args=[o.pk])).status_code,403)
    def test_buyer_can_approve_and_manager_can_receive(self):
        o=PurchaseRequest.objects.create(branch=self.a,category=self.root,requested_by=self.manager)
        item=RequestItem.objects.create(request=o,product=self.p,quantity=3,unit_snapshot='باکس',price_snapshot=100000)
        self.client.force_login(self.buyer)
        self.client.post(reverse('approve_order',args=[o.pk]),{f'approved_{item.pk}':'2'})
        o.refresh_from_db();self.assertEqual(o.status,'approved')
        self.client.post(reverse('change_status',args=[o.pk]),{'status':'dispatched'})
        self.client.force_login(self.manager)
        self.client.post(reverse('receive_order',args=[o.pk]),{f'receive_{item.pk}':'1'})
        o.refresh_from_db();self.assertEqual(o.status,'partial')
        self.assertFalse(Stock.objects.filter(branch=self.a).exists()) # موجودی فقط دستی تغییر می‌کند
        self.client.post(reverse('receive_order',args=[o.pk]),{f'receive_{item.pk}':'1'})
        o.refresh_from_db();self.assertEqual(o.status,'delivered')
    def test_xlsx_response(self):
        o=PurchaseRequest.objects.create(branch=self.a,category=self.root,requested_by=self.manager)
        RequestItem.objects.create(request=o,product=self.p,quantity=3,unit_snapshot='باکس',price_snapshot=100000)
        self.client.force_login(self.manager)
        r=self.client.get(reverse('order_excel',args=[o.pk]))
        self.assertEqual(r.status_code,200)
        self.assertEqual(r.content[:2],b'PK')
    def test_no_status_mutation_by_branch(self):
        o=PurchaseRequest.objects.create(branch=self.a,category=self.root,requested_by=self.manager)
        self.client.force_login(self.manager)
        self.assertEqual(self.client.post(reverse('change_status',args=[o.pk]),{'status':'approved'}).status_code,403)
