from django.shortcuts import render, redirect
from django.db import transaction
from django.contrib import messages
from django.http import JsonResponse
from django.db.models import Q
from datetime import datetime
import json
from .models import slab_letter_table, tx_slab_letter_table
from masters.models import model_table, variant_table, brand_table, sub_category_table
from supplier.models import supplier_table
from django.utils import timezone
import calendar
from common.utils import *
from django.db import IntegrityError, transaction

def slab_letter_list(request):
    try:
        user_type = request.session.get('user_type')
        if user_type == 'stores':

            slab_letters = slab_letter_table.objects.filter(is_active=1).order_by('-id')
            current_month = datetime.now().strftime('%Y-%m')

            # Default month value
            selected_month = current_month

            if request.method == 'POST':
                supplier_id = request.POST.get('supplier_id')
                brand_id = request.POST.get('brand_id')
                month = request.POST.get('month')

                if month:
                    selected_month = month
                    y, m = month.split('-')
                    slab_letters = slab_letters.filter(date__year=y, date__month=m)
                else:
                    # If POST but no month selected → use current
                    y, m = current_month.split('-')
                    slab_letters = slab_letters.filter(date__year=y, date__month=m)

                if supplier_id:
                    slab_letters = slab_letters.filter(supplier_id=supplier_id)

                if brand_id:
                    slab_letters = slab_letters.filter(brand_id=brand_id)

            else:
                # First page load → filter by current month
                y, m = current_month.split('-')
                slab_letters = slab_letters.filter(date__year=y, date__month=m)

            suppliers = supplier_table.objects.filter(status=1)
            brands = brand_table.objects.filter(status=1)
            subcategories = sub_category_table.objects.filter(status=1)

            return render(request, 'slab_letter/details.html', {
                'slab_letters': slab_letters,
                'suppliers': suppliers,
                'brands': brands,
                'subcategories': subcategories,
                'selected_month': selected_month  # ✅ pass to template
            })

        else:
            return redirect('/')

    except Exception as e:
        print(e)
        return render(request, 'slab_letter/details.html')


def slab_letter_add_page(request):
    try:
        user_type = request.session.get('user_type')
        if user_type == 'stores':

            slab_letters = slab_letter_table.objects.filter(is_active=1).order_by('-id')
            current_month = datetime.now().strftime('%Y-%m')
            selected_month = current_month
            suppliers = supplier_table.objects.filter(status=1)
            brands = brand_table.objects.filter(status=1)
            subcategories = sub_category_table.objects.filter(status=1)

            return render(request, 'slab_letter/add.html', {
                'slab_letters': slab_letters,
                'suppliers': suppliers,
                'brands': brands,
                'subcategories': subcategories,
                'selected_month': selected_month  
            })

        else:
            return redirect('/')

    except Exception as e:
        return render(request, 'slab_letter/add.html')
      

def ajax_slab_letter_view(request):
    try:
        user_type = request.session.get('user_type')

        if user_type == 'stores':


            supplier_id = request.POST.get('supplier_id')
            subcategory_id = request.POST.get('subcategory_id')
            brand_id = request.POST.get('brand_id')
            month = request.POST.get('month')  
            print(month)
            query = Q(status = 1)

            # 🔹 Filter supplier
            if supplier_id:
                query &= Q(supplier_id=supplier_id)

            # 🔹 Filter subcategory
            if subcategory_id:
                query &= Q(subcategory_id=subcategory_id)

            # 🔹 Filter brand
            if brand_id:
                query &= Q(brand_id=brand_id)

            # 🔹 Filter by month (convert to date range)
            if month:
                try:
                    year, month_num = map(int, month.split('-'))

                    from_date = datetime(year, month_num, 1).date()

                    # Last day
                    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

            slab_letters = slab_letter_table.objects.filter(query).order_by('-id')
            data = []

            for slab in slab_letters:

                supplier = supplier_table.objects.filter(id=slab.supplier_id).first()
                subcategory = sub_category_table.objects.filter(id=slab.subcategory_id).first()
                brand = brand_table.objects.filter(id=slab.brand_id).first()

                action = f"""
                    <div class="d-flex gap-2">
                        <a href="/slab-letter/edit/{slab.id}/" 
                           class="btn btn-outline-success btn-xs p-1">
                           <i class="fas fa-edit"></i>
                        </a>
                        <button class="btn btn-outline-danger btn-xs p-1" 
                                 onclick="delete_data({slab.id})">
                            <i class="fas fa-trash"></i>
                        </button>
                    </div>
                """

                data.append({
                    "id": slab.id,
                    "month": slab.month if slab.month else '-',
                    "slab_no": slab.slab_no if slab.slab_no else '-',
                    "from_date": slab.from_date.strftime('%d-%m-%Y') if slab.from_date else '-',
                    "to_date": slab.to_date.strftime('%d-%m-%Y') if slab.to_date else '-',
                    "supplier": supplier.name if supplier else f"ID: {slab.supplier_id}",
                    "supplier": supplier.name if supplier else f"ID: {slab.supplier_id}",
                    "brand": brand.name if brand else f"ID: {slab.brand_id}",
                    "employee":  getItemNameById(employee_table, slab.employee_id) if slab.employee_id else '-',
                    "created_at": slab.created_on.strftime('%d-%m-%Y %H:%M') if slab.created_on else '-',
                    'status': '<span class="badge text-bg-success">Active</span>' if slab.is_active else '<span class="badge text-bg-danger">Inactive</span>',

                    '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(slab.id, slab.id),
                })

            return JsonResponse({"data": data}, safe=False)

        else:
            return JsonResponse({"data": [], "message": "unauthorized"}, safe=False)

    except Exception as e:
        print(e)
        return JsonResponse({"data": [], "error": str(e)}, safe=False)

def ajax_load_brand(request):
    if request.method == 'POST':
        subcategory_id = request.POST.get('subcategory_id')
        from masters.models import item_table, brand_table
        brand_ids = item_table.objects.filter(sub_category_id=subcategory_id, is_active=1).values_list('brand_id', flat=True).distinct()
        brands = brand_table.objects.filter(id__in=brand_ids, is_active=1).values('id', 'name')
        return JsonResponse(list(brands), safe=False)
    return JsonResponse([], safe=False)

def ajax_load_subcategories(request):
    if request.method == 'POST':
        brand_id = request.POST.get('brand_id')
        from masters.models import item_table, sub_category_table
        sub_cat_ids = item_table.objects.filter(brand_id=brand_id, is_active=1).values_list('sub_category_id', flat=True).distinct()
        subcategories = sub_category_table.objects.filter(id__in=sub_cat_ids, is_active=1).values('id', 'name')
        return JsonResponse(list(subcategories), safe=False)
    return JsonResponse([], safe=False)

def ajax_load_models(request):
    if request.method == 'POST':
        brand_id = request.POST.get('brand_id')
        subcategory_id = request.POST.get('subcategory_id')
        
        query = Q(brand_id=brand_id, is_active=1)
        if subcategory_id:
            # If subcategory is provided, we might want models that exist in this subcategory for this brand
            from masters.models import item_table
            model_ids = item_table.objects.filter(brand_id=brand_id, sub_category_id=subcategory_id, is_active=1).values_list('model_id', flat=True).distinct()
            models = model_table.objects.filter(id__in=model_ids, is_active=1).values('id', 'name')
        else:
            models = model_table.objects.filter(query).values('id', 'name')
            
        return JsonResponse(list(models), safe=False)
    return JsonResponse([], safe=False)

def ajax_load_variants(request):
    if request.method == 'POST':
        brand_id = request.POST.get('brand_id')
        subcategory_id = request.POST.get('subcategory_id')
        model_id = request.POST.get('model_id')
        
        if subcategory_id and model_id:
            from masters.models import item_table
            variant_ids = item_table.objects.filter(
                brand_id=brand_id, 
                sub_category_id=subcategory_id, 
                model_id=model_id, 
                is_active=1
            ).values_list('variant_id', flat=True).distinct()
            variants = variant_table.objects.filter(id__in=variant_ids, is_active=1).values('id', 'name')
        else:
            variants = variant_table.objects.filter(
                brand_id=brand_id,
                model_id=model_id,
                is_active=1
            ).values('id', 'name')
            
        return JsonResponse(list(variants), safe=False)
    return JsonResponse([], safe=False)




def check_slab_overlap(request):

    supplier_id = request.POST.get('supplier_id')
    subcategory_id = request.POST.get('subcategory_id')
    brand_id   = request.POST.get('brand_id')
    model_id   = request.POST.get('model_id')
    variant_id = request.POST.get('variant_id')
    from_qty   = request.POST.get('from_qty')
    to_qty     = request.POST.get('to_qty')
    month_str  = request.POST.get('month') # expected YYYY-MM
    exclude_id = request.POST.get('exclude_id')

    if not all([supplier_id, brand_id, model_id, variant_id, from_qty, to_qty, month_str]):
        return JsonResponse({'status': False})

    try:
        year, month_num = map(int, month_str.split('-'))
        # Using calendar.month_name[month_num] matches the month string field
        # e.g. "January", "February" ...
        month_name = calendar.month_name[month_num]
    except Exception:
        return JsonResponse({'status': False})

    # Find parent IDs for the target month/year/supplier
    parent_ids = slab_letter_table.objects.filter(
        year=year,
        month=month_name,
        supplier_id=supplier_id,
        status=1
    )
    
    if exclude_id:
        parent_ids = parent_ids.exclude(id=exclude_id)
        
    parent_ids = parent_ids.values_list('id', flat=True)

    overlap_exists = tx_slab_letter_table.objects.filter(
        tm_slab_id__in=parent_ids,
        supplier_id=supplier_id,
        brand_id=brand_id,
        subcategory_id=subcategory_id,
        model_id=model_id,
        variant_id=variant_id,
        is_active=1
    ).filter(
        Q(from_qty__lte=to_qty) &
        Q(to_qty__gte=from_qty)
    ).exists()

    return JsonResponse({
        'status': overlap_exists
    })

import calendar
def add_slab_letter(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, 'slab_letter', "create")
            if not has_access:
                return JsonResponse({
                    'message': 'permission',
                    'error_message': 'You do not have permission to add slab letters.'
                })

            month_str = request.POST.get('month')  # format: YYYY-MM
            supplier_id = request.POST.get('supplier_id')
            brand_id = request.POST.get('brand_id')
            remarks = request.POST.get('remarks')
            items_json = request.POST.get('items')

            if not all([month_str, supplier_id, brand_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 slab row is required.'
                })

            # 🔥 Convert month
            try:
                year, month = map(int, month_str.split('-'))

                # First day
                from_date = datetime(year, month, 1).date()

                # Last day of month
                last_day = calendar.monthrange(year, month)[1]
                to_date = datetime(year, month, last_day).date()

                # Month name (February)
                month_name = from_date.strftime('%B')

            except Exception:
                return JsonResponse({
                    'message': 'warning',
                    'error_message': 'Invalid month format.'
                })

            now = timezone.localtime(timezone.now())
            generated_po_no = generate_serial_number(
                model=slab_letter_table,
                number_field='slab_no',
                financial_year_field='current_fy',
                financial_year=financial_year,
                branch_id=branch_id
            )


            with transaction.atomic():

                # 🔥 Final backend validation for ranges and overlaps
                valid_tm_ids = slab_letter_table.objects.filter(
                    year=year,
                    from_date__month=month,
                    status=1
                ).values_list('id', flat=True)

                for item in items:
                    f_qty = int(item.get('from_qty'))
                    t_qty = int(item.get('to_qty'))
                    m_id = item.get('model_id')
                    v_id = item.get('variant_id')

                    if t_qty <= f_qty:
                        return JsonResponse({
                            'message': 'warning',
                            'error_message': f'Invalid range {f_qty}-{t_qty}. To Quantity must be greater than From Quantity.'
                        })

                    # Final overlap check in DB (Scoped to the target month/year)
                    overlap = tx_slab_letter_table.objects.filter(
                        tm_slab_id__in=valid_tm_ids,
                        subcategory_id=item.get('subcategory_id'),
                        brand_id=brand_id,
                        model_id=m_id,
                        variant_id=v_id,
                        is_active=1
                    ).filter(
                        Q(from_qty__lte=t_qty) & Q(to_qty__gte=f_qty)
                    ).exists()

                    if overlap:
                        return JsonResponse({
                            'message': 'warning',
                            'error_message': f'Slab range {f_qty}-{t_qty} already exists in database!'
                        })

                main_obj = slab_letter_table.objects.create(
                    company_id=company_id,
                    branch_id=branch_id,
                    current_fy=financial_year,
                    date = format_date(now),
                    time = format_hr_m(now),
                    slab_no=generated_po_no,

                    month=month_name,         # 🔥 Save month name
                    from_date=from_date,      # 🔥 Save first date
                    to_date=to_date,          # 🔥 Save last date

                    supplier_id=supplier_id,
                    subcategory_id=None,
                    brand_id=brand_id,
                    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,
                    year=year
                )

                for item in items:
                    tx_slab_letter_table.objects.create(
                        branch_id=branch_id,
                        tm_slab_id=main_obj.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'),
                        from_qty=item.get('from_qty'),
                        to_qty=item.get('to_qty'),
                        amount=item.get('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': 'Slab Letter saved successfully.'
            })

        except Exception as e:
            print(f"Error in add_slab_letter: {e}")
            return JsonResponse({
                'message': 'error',
                'error_message': str(e)
            })

    return JsonResponse({
        'message': 'error',
        'error_message': 'Invalid request method.'
    })


def ajax_slab_edit(request):
    try:
        user_type = request.session.get('user_type')
        if not user_type:
             return JsonResponse({'message': 'error', 'error_message': 'Unauthorized'}, status=403)

        slab_id = request.POST.get('slab_id')
        if not slab_id:
            return JsonResponse({'data': []})

        # Fetch slab items
        items = tx_slab_letter_table.objects.filter(tm_slab_id=slab_id, status=1).values(
            'id', 'model_id', 'variant_id', 'from_qty', 'to_qty', 'amount', 'subcategory_id'
        )
        
        if not items:
            return JsonResponse({'data': []})

        # Collect IDs for bulk fetching names
        model_ids = set(item['model_id'] for item in items if item['model_id'])
        variant_ids = set(item['variant_id'] for item in items if item['variant_id'])
        subcategory_ids = set(item['subcategory_id'] for item in items if item['subcategory_id'])

        # Fetch names
        model_map = {m['id']: m['name'] for m in model_table.objects.filter(id__in=model_ids).values('id', 'name')}
        variant_map = {v['id']: v['name'] for v in variant_table.objects.filter(id__in=variant_ids).values('id', 'name')}
        subcategory_map = {s['id']: s['name'] for s in sub_category_table.objects.filter(id__in=subcategory_ids).values('id', 'name')}

        formatted = []
        for item in items:
            formatted.append({
                'id': item['id'],
                'model_id': item['model_id'],
                'model_name': model_map.get(item['model_id'], ''),
                'subcategory_id': item['subcategory_id'],
                'subcategory_name': subcategory_map.get(item['subcategory_id'], ''),
                'variant_id': item['variant_id'],
                'variant_name': variant_map.get(item['variant_id'], ''),
                'from_qty': item['from_qty'],
                'to_qty': item['to_qty'],
                'amount': item['amount'],
            })

        return JsonResponse({'data': formatted})

    except Exception as e:
        print(f"Error in ajax_slab_edit: {e}")
        return JsonResponse({'data': [], 'error': str(e)})


def slab_letter_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_letter_table, {'id': decoded_id})
                slab_items = selectList(tx_slab_letter_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)
            subcategories = sub_category_table.objects.filter(is_active=1)

            return render(request, 'slab_letter/edit.html', {
                'slab_letter': slab_obj,
                'slab_items': [],
                'suppliers': suppliers,
                'brands': brands,
                'subcategories': subcategories,
                'brand_models': brand_models,
                'brand_variants': brand_variants
            })

        else:
            return redirect('/')

    except Exception as e:
        print(e)
        return redirect('/slab-letter/')
        
        
def update_slab_letter(request):
    if request.method == 'POST':
        try:
            slab_id = request.POST.get('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, 'slab_letter', "update")
            if not has_access:
                return JsonResponse({
                    'message': 'permission',
                    'error_message': 'You do not have permission to update slab letters.'
                })

            slab = select_row(slab_letter_table, {'id': slab_id})
            month_str = request.POST.get('month')
            supplier_id = slab.supplier_id
            brand_id = slab.brand_id
            remarks = request.POST.get('remarks')
            items_json = request.POST.get('items')

            if not all([month_str, supplier_id, brand_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 slab row is required.'
                })

             # Month processing
            try:
                year, month = map(int, month_str.split('-'))
                from_date = datetime(year, month, 1).date()
                last_day = calendar.monthrange(year, month)[1]
                to_date = datetime(year, month, last_day).date()
                month_name = from_date.strftime('%B')
            except Exception:
                return JsonResponse({'message': 'warning', 'error_message': 'Invalid month format.'})

            now = timezone.localtime(timezone.now())

            with transaction.atomic():
            
                # 1. Validation Logic
                valid_tm_ids = slab_letter_table.objects.filter(
                    year=year,
                    from_date__month=month,
                    status=1
                ).exclude(id=slab_id).values_list('id', flat=True)

                for item in items:
                    f_qty = int(item.get('from_qty'))
                    t_qty = int(item.get('to_qty'))
                    m_id = item.get('model_id')
                    v_id = item.get('variant_id')

                    if t_qty <= f_qty:
                         return JsonResponse({
                            'message': 'warning',
                            'error_message': f'Invalid range {f_qty}-{t_qty}. To Quantity must be greater than From Quantity.'
                        })
                        
                    # Check overlap (excluding current document's items)
                    # For update, we are replacing this doc's items, so we should check if these ranges overlap with active items of OTHER slab letters in the SAME month.
                    
                    overlap = tx_slab_letter_table.objects.filter(
                        tm_slab_id__in=valid_tm_ids,
                        subcategory_id=item.get('subcategory_id'),
                        brand_id=brand_id,
                        model_id=m_id,
                        variant_id=v_id,
                        is_active=1
                    ).filter(
                        Q(from_qty__lte=t_qty) & Q(to_qty__gte=f_qty)
                    ).exists()

                    if overlap:
                        return JsonResponse({
                            'message': 'warning',
                            'error_message': f'Slab range {f_qty}-{t_qty} already exists in another slab letter!'
                        })


                # 2. Update Parent
                slab_obj = slab_letter_table.objects.get(id=slab_id)
                slab_obj.month = month_name
                slab_obj.from_date = from_date
                slab_obj.to_date = to_date
                slab_obj.date = from_date # Update main date to 1st of month? Or keep original creation date? Usually update reflects content.
                # Actually user might want to change month.
                
                slab_obj.supplier_id = supplier_id
                slab_obj.subcategory_id = None
                slab_obj.brand_id = brand_id
                slab_obj.remarks = remarks
                slab_obj.updated_on = now
                slab_obj.updated_by = user_id
                slab_obj.save()

                # 3. Soft Delete Old Child Rows
                tx_slab_letter_table.objects.filter(tm_slab_id=slab_id).update(is_active=0, status=0)

                # 4. Create New Child Rows
                for item in items:
                    tx_slab_letter_table.objects.create(
                        branch_id=branch_id,
                        tm_slab_id=slab_obj.id,
                        current_fy=slab_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'),
                        from_qty=item.get('from_qty'),
                        to_qty=item.get('to_qty'),
                        amount=item.get('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': 'Slab Letter updated successfully.'
            })

        except Exception as e:
            print(f"Error in update_slab_letter: {e}")
            return JsonResponse({
                'message': 'error',
                'error_message': str(e)
            })

    return JsonResponse({'message': 'error', 'error_message': 'Invalid request method.'})

