from django.shortcuts import render
import json
from django.conf import settings
from django.shortcuts import render
from inventory.models import *
from expenses.models import *
from store.models import *
from masters.models import *
from stock.models import *
from barcodes.models import *
from django.db import IntegrityError, transaction
from collections import defaultdict
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,FileResponse
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.db import connection
import openpyxl
from openpyxl.styles import Font
from django.http import HttpResponse
from django.core.files.storage import default_storage
from django.shortcuts import get_object_or_404, render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import barcode
from barcode.writer import ImageWriter
from io import BytesIO
import base64
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from django.shortcuts import get_object_or_404, render
from django.http import JsonResponse
from io import BytesIO
import base64
import barcode
from barcode.writer import ImageWriter
from PIL import Image, ImageDraw, ImageFont


# ````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````


def create_barcode_track_entry(company_id, branch_id, financial_year, batch_no, count, total, user_id):
    date_times = timezone.localtime(timezone.now())
    barcode_track_table.objects.create(
        company_id=company_id,
        branch_id=branch_id,
        current_fy=financial_year,
        date=timezone.now().date(),
        time=format_time(date_times),
        batch_no=batch_no,
        count=count,
        total=total,
        is_active=1,
        status=1,
        created_by=user_id,
        updated_by=user_id,
        created_on=timezone.now(),
        updated_on=timezone.now(),
    )





@csrf_exempt
def generate_barcodes(request):
    if request.method != "POST":
        return JsonResponse({'status': 'error', 'message': 'Invalid request method'})

    barcode_id = request.POST.get('barcode_id')
    barcode_type = request.POST.get('barcode_type')
    count = int(request.POST.get('count') or 0)
    role_id = request.session.get('role_id')
    # has_access, error_message = check_user_access(role_id, 'barcode_details', "create")

    # if not has_access:
        # return JsonResponse({'message': 'warning', 'error_message': 'You do not have permission to print barcode details'}) 

    # Session values
    user_id = request.session.get('user_id')
    company_id = request.session.get('company_id')
    branch_id = request.session.get('branch_id')
    fyf_name = request.session.get('fyf')
    financial_year = calculate_financial_year(fyf_name)
    year = str(financial_year).split("-")[0][-2:]


    barcode_images = []

    if barcode_type == 'stock':
        stock = get_object_or_404(opening_stock_table, id=barcode_id)
        item = get_object_or_404(item_table, id=stock.item_id)

        if count > stock.opening_stock:
            return JsonResponse({'status': 'error', 'message': 'Count exceeds available stock'})

        sku_stock = f"{year}/{item.ean}/{stock.stock_no}"
        # sku_stock = f"{item.sku}/{stock.stock_no}"

        for _ in range(count):
            CODE128 = barcode.get_barcode_class('code128')

            
            rv = BytesIO()
           
            options = {
                "module_width": 0.5,   # default ~0.2 (increase for thicker bars)
                "module_height": 15,    # default 15 (increase for taller barcode)
                "font_size": 14,       # size of text under barcode
                "text_distance": 6,  # space between barcode and text
                "quiet_zone": 2,     # blank space around barcode
                "write_text": False
            } 

            code = CODE128("{}".format(sku_stock), writer=ImageWriter())
            code.write(rv, options)
            
          
            image_base64 = base64.b64encode(rv.getvalue()).decode("utf-8")


            barcode_images.append({
                'item_name': limit_text_word_safe(item.ean,31),
                'sku_stock': sku_stock,
                'image': image_base64
            })

        # Common barcode track entry
        create_barcode_track_entry(
            company_id, branch_id, financial_year,
            stock.stock_no, count, stock.opening_stock, user_id
        )

    elif barcode_type == 'purchase':
        child = get_object_or_404(child_purchase_inward_table, id=barcode_id)
        parent = get_object_or_404(purchase_inward_table, id=child.tm_pu_id)
        item = get_object_or_404(item_table, id=child.item_id)

        if count > child.quantity:
            return JsonResponse({'status': 'error', 'message': 'Count exceeds purchase quantity'})

        sku_stock = f"{year}/{item.ean}/{child.imei_no}"

        for _ in range(count):
            CODE128 = barcode.get_barcode_class('code128')
            rv = BytesIO()
            options = {
                "module_width": 0.5,  
                "module_height": 15,  
                "font_size": 14,      
                "text_distance": 6,  
                "quiet_zone": 2,     
                "write_text": False
            } 

            code = CODE128("{}".format(sku_stock), writer=ImageWriter())
            code.write(rv, options)
            # code = CODE128(sku_stock, writer=ImageWriter())
            # code.write(rv)
            image_base64 = base64.b64encode(rv.getvalue()).decode('utf-8')

            barcode_images.append({
                'item_name': limit_text_word_safe(item.ean,31),
                'sku_stock': sku_stock,
                'image': image_base64
            })

        # Common barcode track entry
        create_barcode_track_entry(
            company_id, branch_id, financial_year,
            parent.pu_no, count, child.quantity, user_id
        )

    elif barcode_type == 'all_barcodes':
        purchase_id = request.POST.get('id')
        parent = get_object_or_404(purchase_inward_table, id=purchase_id)

        # Fetch all child items under this purchase
        child_items = child_purchase_inward_table.objects.filter(tm_pu_id=purchase_id, status=1)

        for child in child_items:
            item = get_object_or_404(item_table, id=child.item_id)

            # count = quantity for each child
            count = int(child.quantity or 0) 
            
            sku_stock = f"{year}/{item.ean}/{child.imei_no}"

            for _ in range(count):
                CODE128 = barcode.get_barcode_class('code128')
                rv = BytesIO()
                options = {
                    "module_width": 0.5,    
                    "module_height": 15,    
                    "font_size": 14,        
                    "text_distance": 6,     
                    "quiet_zone": 2,     
                    "write_text": False
                } 
                code = CODE128("{}".format(sku_stock), writer=ImageWriter())
                code.write(rv, options)
                image_base64 = base64.b64encode(rv.getvalue()).decode('utf-8')

                barcode_images.append({
                    'item_name': limit_text_word_safe(item.ean, 31),
                    'sku_stock': sku_stock,
                    'image': image_base64
                })

            # Track entry for each child item
            create_barcode_track_entry(
                company_id, branch_id, financial_year,
                parent.pu_no, count, child.quantity, user_id
            )

    elif barcode_type == 'stock_all_barcodes':
        batch_no = request.POST.get('batch_no')
        item_id = request.POST.get('item_id')
        available_qty = int(request.POST.get('available_qty') or 0)

        # Determine separator
        if "/" in batch_no:
            branch_code, batch_no_split = batch_no.split("/", 1)
        elif "-" in batch_no:
            branch_code, batch_no_split = batch_no.split("-", 1)
        else:
            return JsonResponse({'error': 'Invalid batch number format'})

        # Determine table
        if batch_no_split.upper().startswith("OPN"):
            # It's opening stock
            parent = get_object_or_404(opening_stock_table, stock_no=batch_no, item_id=item_id, status=1)
            item = get_object_or_404(item_table, id=parent.item_id)
        else:
            # It's purchase inward
            child = child_purchase_inward_table.objects.filter(batch_no=batch_no, status=1, item_id=item_id).first()
            if not child:
                return JsonResponse({'error': 'No purchase inward found for batch'})
            item = get_object_or_404(item_table, id=child.item_id)


        sku_stock = f"{year}/{item.sku}/{batch_no}"
        barcode_images = []

        for _ in range(available_qty):
            CODE128 = barcode.get_barcode_class('code128')
            rv = BytesIO()
            options = { 
                "module_width": 0.5,
                "module_height": 15,
                "font_size": 14,
                "text_distance": 6,
                "quiet_zone": 2,
                "write_text": False
            }
            code = CODE128(sku_stock, writer=ImageWriter())
            code.write(rv, options)
            image_base64 = base64.b64encode(rv.getvalue()).decode('utf-8')

            barcode_images.append({
                "item_name": limit_text_word_safe(item.name, 31),
                "sku_stock": sku_stock,
                "image": image_base64
            })

        # Track only if purchase inward
        if not str(batch_no).startswith("OPN"):
            create_barcode_track_entry(
                company_id, branch_id, financial_year,
                batch_no, available_qty, available_qty, user_id
            )


    else:
        return JsonResponse({'status': 'error', 'message': 'Invalid barcode type'})

    request.session['barcode_images'] = barcode_images
    request.session['count'] = count
    return render(request, 'barcode_template.html', {
        'barcodes': barcode_images,
        'tot_data': count
    })

def limit_text_word_safe(text, limit):
    if len(text) <= limit:
        return text
    
    truncated = text[:limit-3]   # leave space for "..."
    if " " in truncated:
        truncated = truncated.rsplit(" ", 1)[0]  # remove the last incomplete word
    
    return truncated + "..."
    
    
def barcode_view(request):
    if request.headers.get('x-requested-with') == 'XMLHttpRequest' and request.method == "POST":
        data = opening_stock_table.objects.filter(id=request.POST.get('id'))    
    return JsonResponse(data.values()[0])


def barcode_page(request):
    barcode_images = request.session.get('barcode_images')    
    count = request.session.get('count') 
    return render(request, 'barcode_template.html', {
        'barcodes': barcode_images,
        'tot_data': count
    })


