from django.shortcuts import render
import json
from django.conf import settings
from django.shortcuts import render
from sales.models import *
from expenses.models import *
from store.models import *
from masters.models import *
from stock.models import *
from material.models import *

from collections import defaultdict
from sales.forms import *
from django.db import IntegrityError, transaction
import hashlib
import os
from django.conf import settings
from datetime import datetime
from django.utils import timezone
from django.db.models import Max, F, Q,Sum
import base64
from django.shortcuts import render
from io import BytesIO
from django.conf import settings
from django.template.loader import get_template
from django.http import HttpResponse,HttpResponseRedirect,JsonResponse
from django.shortcuts import get_object_or_404
from django.templatetags.static import static
from xhtml2pdf import pisa
from num2words import num2words
from django.contrib.staticfiles import finders
from common.utils import *
from django.views.decorators.csrf import csrf_exempt
from supplier.models import *
from django.db import connection
from customer.models import *
from django.db import transaction as db_transaction
from slab.models import *

#```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````

def slabwise_sales(request):
    if 'user_id' in request.session:
        user_type = request.session.get('user_type')
        branch_id = request.session.get('branch_id')
        is_ho = request.session.get('is_ho')
        selected_month = datetime.now().strftime('%Y-%m')
        if user_type == 'stores':
            if is_ho == 1:
                supplier = selectList(supplier_table, order_by='name' )
            slab = selectList(slab_letter_table)   
            branch = selectList(branch_table, order_by='name')
            brand = selectList(brand_table, order_by='name')
            

            return render(request, 'slab_sales/details.html',{'supplier':supplier,'branch':branch,'slab':slab,'brand':brand,'selected_month':selected_month})
        else:
            return HttpResponseRedirect("/")
    else:
        return HttpResponseRedirect("/")
    

import calendar

def ajax_slab_sales_details(request):
    role_id = request.session.get('role_id')
    branch_id = request.session.get('branch_id')
    fyf_name = request.session.get('fyf')
    financial_year = calculate_financial_year(fyf_name)
             
    has_access, error_message = check_user_access(role_id, 'purchase_order', "read")

    if not has_access:
        return JsonResponse({'message': 'permission', 'error_message': 'You do not have permission to view purchase order details'})
    
    supplier_id = request.POST.get('supplier')
    supply_id = request.POST.get('branch_id')
    brand_id = request.POST.get('brand_id')
    month = request.POST.get('month')
    keyword = request.POST.get('keyword_search', '').strip()

    query = Q(status=1, branch_id=branch_id, current_fy = financial_year)

    if supplier_id:
        query &= Q(supplier_id=supplier_id)

    if supply_id:
        query &= Q(supply_branch_id=supply_id)

    if brand_id:
        query &= Q(brand_id=brand_id)

    if month:
        try:
            year, month_num = map(int, month.split('-'))

            from_date = datetime(year, month_num, 1).date()

            last_day = calendar.monthrange(year, month_num)[1]
            to_date = datetime(year, month_num, last_day).date()
            query &= Q(date__range=[from_date, to_date])
        except Exception:
            pass  # ignore invalid month format safely
       
    
    
    data = list(selectList(slab_sales_table, query).values())

    formatted = []
    for index, item in enumerate(data):    
        # Get distinct slab_letter_ids from tx_table
        letter_ids = list(tx_slab_sales_table.objects.filter(tm_slab_id=item['id'], status=1).values_list('slab_letter_id', flat=True).distinct())
        slabs = slab_letter_table.objects.filter(id__in=letter_ids)
        
        slab_nos = ", ".join([s.slab_no for s in slabs]) if slabs else '-'
        slab_months = ", ".join([s.month for s in slabs]) if slabs else '-'
       
        formatted.append({
            'id': index + 1,
            'action': '<button type="button" onclick="edit_data(\'{}\')" class="btn btn-outline-success btn-xs p-1"><i class="fas fa-edit"></i></button> \
                      <button type="button" onclick="delete_data(\'{}\')" class="btn btn-outline-danger btn-xs p-1"> <i class="fas fa-trash-alt"></i></button>'.format(item['id'], item['id']), 
            'slab_letter_no': slab_nos,
            'slab_letter_month': slab_months,
            'slab_no': item['slab_no'] if item['slab_no'] else '-', 
            'month': item['month'] if item['month'] else '-', 
            'supplier': getItemNameById(supplier_table, item['supplier_id']) if item['supplier_id'] else '-', 
            'branch': getItemNameById(branch_table, item['supply_branch_id']) if item['supply_branch_id'] else '-',            
            'credit_note': format_amount(item['credit_note']),            
            'claim_amount': format_amount(item['claim_amount']),            
            'employee': getItemNameById(employee_table, item['employee_id']) if item['employee_id'] else '-',            
            'claim_status': format_badge(item['claim_status'], mapping={
                'pending': 'badge text-bg-info',
                'claimed': 'badge text-bg-success',
                'partial': 'badge text-bg-warning'
            }, label_mapping={
                'pending': 'Pending',
                'claimed': 'Claimed',
                'partial': 'Partial'
            }),
        })


    return JsonResponse({'data': formatted})




def slabwise_sales_add(request):
    if 'user_id' in request.session:
        user_type = request.session.get('user_type')
        branch_id = request.session.get('branch_id')
        is_ho = request.session.get('is_ho')
        if user_type == 'stores':
            suppliers = selectList(supplier_table, order_by='name' )
            slabs = selectList(slab_letter_table)   
            branch = selectList(branch_table, order_by='name')
            brands = selectList(brand_table, order_by='name')
            
            selected_month = datetime.now().strftime('%Y-%m')

            return render(request, 'slab_sales/add.html', {
                'suppliers': suppliers, 
                'branch': branch, 
                'slabs': slabs, 
                'brands': brands,
                'selected_month': selected_month
            })
        else:
            return HttpResponseRedirect("/")
    else:
        return HttpResponseRedirect("/")

def ajax_get_slab_details(request):
    slab_id = request.GET.get('slab_id')
    edit_id = request.GET.get('edit_id') or 0
    
    try:
        slab = slab_letter_table.objects.get(id=slab_id)
        
        # Check if this slab letter has already been used in Slabwise Sales
        exists_query = slab_sales_table.objects.filter(slab_id=slab_id, status=1)
        if edit_id:
            exists_query = exists_query.exclude(id=edit_id)
            
        already_exists = exists_query.exists()
        
        return JsonResponse({
            'status': 'success',
            'supplier_id': slab.supplier_id,
            'brand_id': slab.brand_id,
            'already_exists': already_exists
        })
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)})
def ajax_get_slab_sales(request):
    branch_id = request.GET.get('branch_id')
    brand_id = request.GET.get('brand_id')
    month = request.GET.get('month')
    slab_id = request.GET.get('slab_id')
    supplier_id = request.GET.get('supplier_id')
    edit_id = request.GET.get('edit_id') or 0

    if not all([brand_id, month, slab_id]):
        return JsonResponse({'status': 'error', 'message': 'Missing parameters'})

    try:
        # 🔹 Convert Month
        year, month_num = map(int, month.split('-'))
        from_date = datetime(year, month_num, 1).date()
        last_day = calendar.monthrange(year, month_num)[1]
        to_date = datetime(year, month_num, last_day).date()

        # ==========================================================
        # 🔥 CHECK IF ALREADY GENERATED
        # ==========================================================
        if branch_id:
            existing_slab = slab_sales_table.objects.filter(
                supply_branch_id=branch_id,
                supplier_id=supplier_id,
                brand_id=brand_id,
                from_date=from_date,
                to_date=to_date,
                slab_id=slab_id,
                status=1
            )

            if edit_id:
                existing_slab = existing_slab.exclude(id=edit_id)

            if existing_slab.exists():
                return JsonResponse({
                    'status': 'error',
                    'message': f'Slab sales already generated for this month under Branch {getItemNameById(branch_table, branch_id)}'
                })

        # ==========================================================
        # 🔹 SALES
        # ==========================================================
        sales_query = Q(inv_date__range=[from_date, to_date], status=1, sales_status='approved')
        if branch_id:
            sales_query &= Q(branch_id=branch_id)

        sales_ids = sales_order_table.objects.filter(sales_query).values_list('id', flat=True)

        sales_data = child_sales_order_table.objects.filter(
            tm_sales_id__in=sales_ids,
            brand_id=brand_id,
            status=1
        ).values(
            'brand_id', 'model_id', 'variant_id', 'subcategory_id', 'branch_id'
        ).annotate(total_sales=Sum('quantity'))

        # ==========================================================
        # 🔹 RETURNS
        # ==========================================================
        return_query = Q(sr_date__range=[from_date, to_date], status=1)
        if branch_id:
            return_query &= Q(branch_id=branch_id)

        return_ids = sales_return_table.objects.filter(return_query).values_list('id', flat=True)

        return_data = child_sales_return_table.objects.filter(
            tm_return_id__in=return_ids,
            brand_id=brand_id,
            status=1
        ).values(
            'brand_id', 'model_id', 'variant_id', 'subcategory_id', 'branch_id'
        ).annotate(total_returns=Sum('quantity'))

        # ==========================================================
        # 🔹 COMBINE SALES - RETURNS
        # ==========================================================
        final_sales = defaultdict(int)

        for s in sales_data:
            key = (s['brand_id'], s['model_id'], s['variant_id'], s['subcategory_id'], s['branch_id'])
            final_sales[key] += s['total_sales']

        for r in return_data:
            key = (r['brand_id'], r['model_id'], r['variant_id'], r['subcategory_id'], r['branch_id'])
            final_sales[key] -= r['total_returns']

        # ==========================================================
        # 🔹 APPLY SLAB LOGIC (FIXED)
        # ==========================================================
        results = []

        for (b_id, m_id, v_id, sub_id, br_id), qty in final_sales.items():
            if qty <= 0:
                continue

            slab_rows = tx_slab_letter_table.objects.filter(
                tm_slab_id=slab_id,
                brand_id=b_id,
                subcategory_id=sub_id,
                model_id=m_id,
                variant_id=v_id,
                status=1
            )
            print('slab_rows',slab_rows, 'Slab', slab_id, 'Brand', b_id, 'Model', m_id, 'Variant', v_id, 'Subcategory', sub_id, 'Branch', br_id, 'Qty', qty)

            slab_amount = 0

            # 🔥 Loop through slabs to match correct range
            for slab in slab_rows:
                if slab.from_qty <= qty <= slab.to_qty:
                    slab_amount = float(slab.amount)
                    break

            total = slab_amount * qty

            results.append({
                'branch_id': br_id,
                'branch_name': getItemNameById(branch_table, br_id),
                'brand_id': b_id,
                'brand_name': getItemNameById(brand_table, b_id),
                'subcategory_name': getItemNameById(sub_category_table, sub_id),
                'subcategory_id': sub_id,
                'model_id': m_id,
                'model_name': getItemNameById(model_table, m_id),
                'variant_id': v_id,
                'variant_name': getItemNameById(variant_table, v_id),
                'sales_qty': qty,
                'slab_amount': slab_amount,
                'total': total
            })

        return JsonResponse({'status': 'success', 'data': results})

    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)})

def add_slabwise_sales(request):
    if request.method == 'POST':
        try:
            company_id = request.session.get('company_id')
            branch_id = request.session.get('branch_id')
            user_id = request.session.get('user_id')
            fyf_name = request.session.get('fyf')
            financial_year = calculate_financial_year(fyf_name)
            role_id = request.session.get('role_id')

            has_access, error_message = check_user_access(role_id, 'slabwise_sales', "create")
            if not has_access:
                return JsonResponse({
                    'message': 'permission',
                    'error_message': 'You do not have permission to add slabwise sales.'
                })

            month_str = request.POST.get('month')  # YYYY-MM
            supplier_id = request.POST.get('supplier_id')
            brand_id = request.POST.get('brand_id')
            slab_id = request.POST.get('slab_letter')
            supply_branch_id = request.POST.get('store_id')
            remarks = request.POST.get('remarks')
            items_json = request.POST.get('items')

            if not all([month_str, supplier_id, brand_id, slab_id, items_json]):
                return JsonResponse({
                    'message': 'warning',
                    'error_message': 'Required fields are missing.'
                })

            items = json.loads(items_json)
            if not items:
                return JsonResponse({
                    'message': 'warning',
                    'error_message': 'At least one sales row is required.'
                })

            # 🔥 Convert month
            year, month_num = map(int, month_str.split('-'))
            from_date = datetime(year, month_num, 1).date()
            last_day = calendar.monthrange(year, month_num)[1]
            to_date = datetime(year, month_num, last_day).date()
            month_name = from_date.strftime('%B')

            now = timezone.localtime(timezone.now())
            slab_letter_obj = slab_letter_table.objects.get(id=slab_id)

            # Prevent duplicate claims for same Store, Slab and Month
            existing_claim = slab_sales_table.objects.filter(
                slab_id=slab_id,
                # supply_branch_id=supply_branch_id,
                from_date=from_date,
                status=1
            ).exists()

            if existing_claim:
                return JsonResponse({
                    'message': 'warning',
                    'error_message': 'A Slabwise Sales claim already exists for this Store, Slab Letter, and Month.'
                })

            with db_transaction.atomic():
                # Calculate total claim amount
                total_claim = sum(float(item.get('total_amount', 0)) for item in items)

                main_obj = slab_sales_table.objects.create(
                    company_id=company_id,
                    branch_id=branch_id,
                    current_fy=financial_year,
                    slab_id=slab_id,
                    supply_branch_id=0,
                    supplier_id=supplier_id,
                    brand_id=brand_id,
                    from_date=from_date,
                    to_date=to_date,
                    date=format_date(now),
                    time=format_time(now),
                    slab_no=slab_letter_obj.slab_no,
                    credit_note=total_claim,
                    month=month_name,
                    year=year,
                    remarks=remarks,
                    is_active=1,
                    status=1,
                    created_on=now,
                    updated_on=now,
                    employee_id=user_id,
                    created_by=user_id,
                    updated_by=user_id
                )

                for item in items:
                    print('Supply', item.get('supply_branch_id'))
                    
                    tx_slab_sales_table.objects.create(
                        branch_id=branch_id,
                        supply_branch_id=item.get('supply_branch_id'),
                        tm_slab_id=main_obj.id,
                        slab_letter_id=slab_id,
                        current_fy=financial_year,
                        supplier_id=supplier_id,
                        subcategory_id=item.get('subcategory_id'),
                        brand_id=brand_id,
                        model_id=item.get('model_id'),
                        variant_id=item.get('variant_id'),
                        sales_qty=item.get('sales_qty'),
                        slab_amount=item.get('slab_amount'),
                        total_amount=item.get('total_amount'),
                        is_active=1,
                        status=1,
                        created_on=now,
                        updated_on=now,
                        created_by=user_id,
                        updated_by=user_id
                    )

            return JsonResponse({
                'message': 'success',
                'success_message': 'Slabwise Sales saved successfully.'
            })

        except Exception as e:
            print(f"Error in add_slabwise_sales: {e}")
            return JsonResponse({
                'message': 'error',
                'error_message': str(e)
            })

    return JsonResponse({
        'message': 'error',
        'error_message': 'Invalid request method.'
    })

def slab_sales_edit_page(request):
    try:
        user_type = request.session.get('user_type')
        print(user_type)
        if user_type == 'stores':            
            encoded_id = request.GET.get('id', None)
            decoded_id = decode_base64_id(encoded_id)
            if decoded_id:
                slab_obj = select_row(slab_sales_table, {'id': decoded_id})
                slab_items = selectList(tx_slab_sales_table, {'tm_slab_id': decoded_id})

            # Preload dropdowns for the selected brand
            brand_id = slab_obj.brand_id
            brand_models = model_table.objects.filter(brand_id=brand_id, is_active=1)
            brand_variants = variant_table.objects.filter(brand_id=brand_id, is_active=1)

            suppliers = supplier_table.objects.filter(is_active=1)
            brands = brand_table.objects.filter(is_active=1)
            branch = branch_table.objects.filter(is_active=1)
            slabs = slab_letter_table.objects.filter(is_active=1)

            return render(request, 'slab_sales/edit.html', {
                'slab_sales': slab_obj,
                'slab_items': [],
                'suppliers': suppliers,
                'brands': brands,
                'branch': branch,
                'slabs': slabs,
                'brand_models': brand_models,
                'brand_variants': brand_variants
            })

        else:
            return HttpResponseRedirect('/')

    except Exception as e:
        print(e)
        return HttpResponseRedirect('/')


def ajax_get_saved_slab_sales_items(request):
    try:
        tm_id = request.GET.get('tm_slab_id')
        if not tm_id:
            return JsonResponse({'status': 'error', 'message': 'Missing ID'})

        items = tx_slab_sales_table.objects.filter(tm_slab_id=tm_id, status=1)
        data = []
        for item in items:
            data.append({
                'branch_id': item.supply_branch_id,
                'branch_name': getItemNameById(branch_table, item.supply_branch_id),
                'brand_id': item.brand_id,
                'brand_name': getItemNameById(brand_table, item.brand_id),
                'subcategory_id': item.subcategory_id,
                'subcategory_name': getItemNameById(sub_category_table, item.subcategory_id),
                'model_id': item.model_id,
                'model_name': getItemNameById(model_table, item.model_id),
                'variant_id': item.variant_id,
                'variant_name': getItemNameById(variant_table, item.variant_id),
                'sales_qty': item.sales_qty,
                'slab_amount': float(item.slab_amount),
                'total_amount': float(item.total_amount)
            })
        return JsonResponse({'status': 'success', 'data': data})
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)})


def update_slabwise_sales(request):
    if request.method == 'POST':
        try:
            slab_sales_id = request.POST.get('slab_sales_id')
            company_id = request.session.get('company_id')
            branch_id = request.session.get('branch_id')
            user_id = request.session.get('user_id')
            role_id = request.session.get('role_id')

            has_access, error_message = check_user_access(role_id, 'slabwise_sales', "update")
            if not has_access:
                return JsonResponse({
                    'message': 'permission',
                    'error_message': 'You do not have permission to update slabwise sales.'
                })

            month_str = request.POST.get('month')
            supplier_id = request.POST.get('supplier_id')
            brand_id = request.POST.get('brand_id')
            slab_id = request.POST.get('slab_letter')
            supply_branch_id = request.POST.get('store_id')
            remarks = request.POST.get('remarks')
            items_json = request.POST.get('items')

            if not all([slab_sales_id, month_str, supplier_id, brand_id, slab_id, supply_branch_id, items_json]):
                return JsonResponse({
                    'message': 'warning',
                    'error_message': 'Required fields are missing.'
                })

            items = json.loads(items_json)
            if not items:
                return JsonResponse({'message': 'warning', 'error_message': 'At least one sales row is required.'})

            year, month_num = map(int, month_str.split('-'))
            from_date = datetime(year, month_num, 1).date()
            last_day = calendar.monthrange(year, month_num)[1]
            to_date = datetime(year, month_num, last_day).date()
            month_name = from_date.strftime('%B')

            now = timezone.localtime(timezone.now())
            slab_letter_obj = slab_letter_table.objects.get(id=slab_id)

            with db_transaction.atomic():
                total_claim = sum(float(item.get('total_amount', 0)) for item in items)

                main_obj = slab_sales_table.objects.get(id=slab_sales_id)
                main_obj.slab_id = slab_id
                main_obj.supply_branch_id = supply_branch_id
                main_obj.supplier_id = supplier_id
                main_obj.brand_id = brand_id
                main_obj.from_date = from_date
                main_obj.to_date = to_date
                main_obj.month = month_name
                main_obj.year = year
                main_obj.remarks = remarks
                main_obj.credit_note = total_claim
                main_obj.updated_on = now
                main_obj.updated_by = user_id
                main_obj.save()

                # Soft delete old tx rows
                tx_slab_sales_table.objects.filter(tm_slab_id=slab_sales_id).update(is_active=0, status=0)

                for item in items:
                    tx_slab_sales_table.objects.create(
                        branch_id=branch_id,
                        supply_branch_id=supply_branch_id,
                        tm_slab_id=main_obj.id,
                        slab_letter_id=slab_id,
                        current_fy=main_obj.current_fy,
                        supplier_id=supplier_id,
                        subcategory_id=item.get('subcategory_id'),
                        brand_id=brand_id,
                        model_id=item.get('model_id'),
                        variant_id=item.get('variant_id'),
                        sales_qty=item.get('sales_qty'),
                        slab_amount=item.get('slab_amount'),
                        total_amount=item.get('total_amount'),
                        is_active=1,
                        status=1,
                        created_on=now,
                        updated_on=now,
                        created_by=user_id,
                        updated_by=user_id
                    )

            return JsonResponse({
                'message': 'success',
                'success_message': 'Slabwise Sales updated successfully.'
            })

        except Exception as e:
            print(f"Error in update_slabwise_sales: {e}")
            return JsonResponse({'message': 'error', 'error_message': str(e)})

    return JsonResponse({'message': 'error', 'error_message': 'Invalid request method.'})