import os
import platform
import io
import base64
import json
import pandas as pd
from datetime import timedelta, datetime
from django import get_version as django_version
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from django.db.models import Sum, Q
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import JsonResponse, HttpResponse
from .models import Medicine, Batch, Category, StockTransaction, Supplier, Faktur, AppSetting
from .forms import SupplierForm, FakturForm, StockInForm, StockOutForm, CategoryForm, MedicineForm, AppSettingForm

from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, A4
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle

from ai.local_ai_api import LocalAIApi

@login_required
def home(request):
    """Render the medicine warehouse dashboard."""
    now = timezone.now()
    today = now.date()
    
    settings = AppSetting.objects.first()
    project_name = settings.app_name if settings else "DN-WRS"
    
    # Stats
    total_medicines = Medicine.objects.count()
    
    # Total stock across all batches
    total_stock = Batch.objects.aggregate(total=Sum('quantity'))['total'] or 0
    
    # Expired batches
    expired_batches_count = Batch.objects.filter(expiry_date__lte=today).count()
    
    # Near expiry (next 90 days)
    near_expiry_batches_count = Batch.objects.filter(
        expiry_date__gt=today, 
        expiry_date__lte=today + timezone.timedelta(days=90)
    ).count()

    # Low stock medicines
    all_medicines = Medicine.objects.all()
    low_stock_count = 0
    for med in all_medicines:
        if med.total_stock <= med.min_stock:
            low_stock_count += 1

    # Latest medicines for the table
    recent_medicines = all_medicines.order_by('-created_at')[:5]

    # Chart Data: Last 7 days movement
    chart_labels = []
    chart_data_in = []
    chart_data_out = []
    
    for i in range(6, -1, -1):
        day = today - timedelta(days=i)
        chart_labels.append(day.strftime('%d %b'))
        
        in_sum = StockTransaction.objects.filter(
            transaction_type='IN',
            created_at__date=day
        ).aggregate(total=Sum('quantity'))['total'] or 0
        
        out_sum = StockTransaction.objects.filter(
            transaction_type='OUT',
            created_at__date=day
        ).aggregate(total=Sum('quantity'))['total'] or 0
        
        chart_data_in.append(in_sum)
        chart_data_out.append(out_sum)

    context = {
        "project_name": project_name,
        "total_medicines": total_medicines,
        "total_stock": total_stock,
        "expired_count": expired_batches_count,
        "near_expiry_count": near_expiry_batches_count,
        "low_stock_count": low_stock_count,
        "recent_medicines": recent_medicines,
        "chart_labels": chart_labels,
        "chart_data_in": chart_data_in,
        "chart_data_out": chart_data_out,
        "django_version": django_version(),
        "python_version": platform.python_version(),
        "current_time": now,
    }
    return render(request, "core/index.html", context)

@login_required
def app_settings(request):
    settings = AppSetting.objects.first()
    if not settings:
        settings = AppSetting.objects.create(app_name="DN-WRS")
    
    if request.method == 'POST':
        form = AppSettingForm(request.POST, instance=settings)
        if form.is_valid():
            form.save()
            messages.success(request, "Pengaturan aplikasi berhasil diperbarui.")
            return redirect('app_settings')
    else:
        form = AppSettingForm(instance=settings)
    
    return render(request, 'core/settings.html', {'form': form, 'settings': settings})

# --- MASTER DATA MANAGEMENT ---

@login_required
def category_list(request):
    if request.method == 'POST':
        form = CategoryForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Kategori berhasil ditambahkan.")
            return redirect('category_list')
    else:
        form = CategoryForm()
    
    categories = Category.objects.all().order_by('name')
    return render(request, 'core/categories.html', {
        'categories': categories,
        'form': form
    })

@login_required
def supplier_list(request):
    if request.method == 'POST':
        form = SupplierForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Supplier berhasil ditambahkan.")
            return redirect('supplier_list')
    else:
        form = SupplierForm()
    
    suppliers = Supplier.objects.all().order_by('name')
    return render(request, 'core/suppliers.html', {
        'suppliers': suppliers,
        'form': form
    })

@login_required
def medicine_list(request):
    query = request.GET.get('q')
    show_low_stock = request.GET.get('low_stock') == '1'
    
    if request.method == 'POST':
        form = MedicineForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Data barang berhasil ditambahkan.")
            return redirect('medicine_list')
    else:
        form = MedicineForm()

    medicines_all = Medicine.objects.all().order_by('name')
    
    # Calculate low stock count for the summary
    low_stock_count = 0
    for med in medicines_all:
        if med.total_stock <= med.min_stock:
            low_stock_count += 1
            
    medicines = medicines_all
    
    if query:
        medicines = medicines.filter(
            Q(name__icontains=query) | 
            Q(sku__icontains=query) |
            Q(category__name__icontains=query)
        )
    
    if show_low_stock:
        # Filter for low stock
        low_stock_ids = [m.id for m in medicines if m.total_stock <= m.min_stock]
        medicines = medicines.filter(id__in=low_stock_ids)

    return render(request, 'core/medicines.html', {
        'medicines': medicines,
        'form': form,
        'query': query,
        'show_low_stock': show_low_stock,
        'low_stock_count': low_stock_count,
        'total_count': medicines_all.count()
    })

@login_required
def export_low_stock_pdf(request):
    # Get low stock medicines
    all_medicines = Medicine.objects.all().order_by('main_supplier__name', 'name')
    low_stock_medicines = [m for m in all_medicines if m.total_stock <= m.min_stock]
    
    # Group by main supplier
    grouped = {}
    for m in low_stock_medicines:
        supplier_name = m.main_supplier.name if m.main_supplier else "Tanpa Supplier Utama"
        if supplier_name not in grouped:
            grouped[supplier_name] = []
        grouped[supplier_name].append(m)
    
    # Generate PDF
    buffer = io.BytesIO()
    doc = SimpleDocTemplate(buffer, pagesize=A4)
    elements = []
    styles = getSampleStyleSheet()
    
    title_style = ParagraphStyle(
        'Title',
        parent=styles['Heading1'],
        fontSize=18,
        alignment=1,
        spaceAfter=20,
        textColor=colors.HexColor("#0d6efd")
    )
    
    elements.append(Paragraph("Laporan Daftar Stok Menipis", title_style))
    elements.append(Paragraph(f"Tanggal Cetak: {timezone.now().strftime('%d %B %Y %H:%M')}", styles["Normal"]))
    elements.append(Spacer(1, 20))
    
    if not low_stock_medicines:
        elements.append(Paragraph("Tidak ada stok yang menipis saat ini.", styles["Normal"]))
    else:
        for supplier, items in grouped.items():
            elements.append(Paragraph(f"Supplier Utama: {supplier}", styles["Heading2"]))
            elements.append(Spacer(1, 5))
            
            data = [["Nama Barang", "SKU", "Stok", "Min.", "Satuan", "Supplier Alternatif"]]
            for item in items:
                alt_supplier = item.alternative_supplier.name if item.alternative_supplier else "-"
                data.append([
                    item.name, 
                    item.sku, 
                    str(item.total_stock), 
                    str(item.min_stock), 
                    item.unit,
                    alt_supplier
                ])
            
            table = Table(data, colWidths=[160, 60, 40, 40, 50, 110])
            table.setStyle(TableStyle([
                ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#343a40")),
                ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTSIZE', (0, 0), (-1, 0), 10),
                ('BOTTOMPADDING', (0, 0), (-1, 0), 10),
                ('TOPPADDING', (0, 0), (-1, 0), 10),
                ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
                ('FONTSIZE', (0, 1), (-1, -1), 9),
            ]))
            elements.append(table)
            elements.append(Spacer(1, 15))
        
    doc.build(elements)
    
    buffer.seek(0)
    response = HttpResponse(buffer, content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="laporan_stok_menipis.pdf"'
    return response

# --- TRANSAKSI ---

@login_required
def input_faktur(request):
    if request.method == 'POST':
        faktur_form = FakturForm(request.POST)
        if faktur_form.is_valid():
            faktur = faktur_form.save()
            return redirect('faktur_detail', pk=faktur.pk)
    else:
        faktur_form = FakturForm(initial={'faktur_type': 'MASUK', 'date': timezone.now().date()})
    
    fakturs = Faktur.objects.all().order_by('-created_at')
    return render(request, 'core/input_faktur.html', {
        'faktur_form': faktur_form,
        'fakturs': fakturs
    })

@login_required
def faktur_detail(request, pk):
    faktur = get_object_or_404(Faktur, pk=pk)
    if request.method == 'POST':
        if 'add_item' in request.POST:
            form = StockInForm(request.POST)
            if form.is_valid():
                # Create Batch
                batch = Batch.objects.create(
                    medicine=form.cleaned_data['medicine'],
                    faktur=faktur,
                    batch_number=form.cleaned_data['batch_number'],
                    expiry_date=form.cleaned_data['expiry_date'],
                    quantity=form.cleaned_data['quantity'],
                    buying_price=form.cleaned_data['buying_price'],
                    selling_price=form.cleaned_data['selling_price']
                )
                # Create Transaction
                StockTransaction.objects.create(
                    medicine=batch.medicine,
                    batch=batch,
                    faktur=faktur,
                    transaction_type='IN',
                    quantity=batch.quantity,
                    note=f"Input dari Faktur {faktur.faktur_number}"
                )
                messages.success(request, f"Barang {batch.medicine.name} berhasil ditambahkan.")
                return redirect('faktur_detail', pk=pk)
    else:
        form = StockInForm()
    
    items = Batch.objects.filter(faktur=faktur)
    cart = request.session.get('import_cart', [])
    cart_faktur_id = request.session.get('cart_faktur_id')
    
    # Only show cart if it belongs to this faktur
    show_cart = cart and cart_faktur_id == pk

    return render(request, 'core/faktur_detail.html', {
        'faktur': faktur,
        'form': form,
        'items': items,
        'cart': cart if show_cart else []
    })

@login_required
def barang_keluar(request):
    if request.method == 'POST':
        form = StockOutForm(request.POST)
        if form.is_valid():
            medicine = form.cleaned_data['medicine']
            batch = form.cleaned_data['batch']
            qty = form.cleaned_data['quantity']
            
            if batch.quantity < qty:
                messages.error(request, f"Stok tidak mencukupi. Stok saat ini: {batch.quantity}")
            else:
                # Update Batch
                batch.quantity -= qty
                batch.save()
                
                # Create Transaction
                StockTransaction.objects.create(
                    medicine=medicine,
                    batch=batch,
                    transaction_type='OUT',
                    quantity=qty,
                    note=form.cleaned_data['note']
                )
                messages.success(request, f"Barang keluar berhasil dicatat.")
                return redirect('barang_keluar')
    else:
        form = StockOutForm()
    
    transactions = StockTransaction.objects.filter(transaction_type='OUT').order_by('-created_at')[:10]
    cart = request.session.get('export_cart', [])

    return render(request, 'core/barang_keluar.html', {
        'form': form,
        'transactions': transactions,
        'cart': cart
    })

@login_required
def get_batches(request):
    medicine_id = request.GET.get('medicine_id')
    batches = Batch.objects.filter(medicine_id=medicine_id, quantity__gt=0).values('id', 'batch_number', 'quantity')
    return JsonResponse(list(batches), safe=False)

@login_required
def laporan_transaksi(request):
    transactions = StockTransaction.objects.all().order_by('-created_at')
    return render(request, 'core/laporan_transaksi.html', {
        'transactions': transactions
    })

@login_required
def delete_transaksi(request, pk):
    transaction = get_object_or_404(StockTransaction, pk=pk)
    batch = transaction.batch
    
    if batch:
        if transaction.transaction_type == 'IN':
            batch.quantity -= transaction.quantity
        elif transaction.transaction_type == 'OUT':
            batch.quantity += transaction.quantity
        batch.save()
    
    transaction.delete()
    messages.success(request, "Transaksi berhasil dihapus dan stok telah diperbarui.")
    return redirect('laporan_transaksi')

@login_required
def edit_transaksi(request, pk):
    transaction = get_object_or_404(StockTransaction, pk=pk)
    if request.method == 'POST':
        new_qty = int(request.POST.get('quantity'))
        old_qty = transaction.quantity
        batch = transaction.batch
        
        if batch:
            if transaction.transaction_type == 'IN':
                # Revert old, apply new
                batch.quantity = batch.quantity - old_qty + new_qty
            elif transaction.transaction_type == 'OUT':
                # Revert old, apply new
                batch.quantity = batch.quantity + old_qty - new_qty
            
            if batch.quantity < 0:
                messages.error(request, "Error: Stok tidak boleh negatif setelah perubahan.")
                return redirect('laporan_transaksi')
            
            batch.save()
        
        transaction.quantity = new_qty
        transaction.note = request.POST.get('note', transaction.note)
        transaction.save()
        messages.success(request, "Transaksi berhasil diperbarui.")
        return redirect('laporan_transaksi')
    
    return render(request, 'core/edit_transaksi.html', {
        'transaction': transaction
    })

# --- IMPORT / EXCEL / OCR ---

@login_required
def download_template(request, type):
    if type == 'masuk':
        cols = ['SKU', 'Nama Barang', 'Batch', 'Expiry Date (YYYY-MM-DD)', 'Qty', 'Harga Beli', 'Harga Jual']
        filename = 'template_barang_masuk.xlsx'
    else:
        cols = ['SKU', 'Batch Number', 'Qty', 'Catatan']
        filename = 'template_barang_keluar.xlsx'
    
    df = pd.DataFrame(columns=cols)
    buffer = io.BytesIO()
    with pd.ExcelWriter(buffer, engine='openpyxl') as writer:
        df.to_excel(writer, index=False)
    
    buffer.seek(0)
    response = HttpResponse(buffer.read(), content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    response['Content-Disposition'] = f'attachment; filename={filename}'
    return response

@login_required
def import_excel(request, type, faktur_id=None):
    if request.method == 'POST' and request.FILES.get('file'):
        file = request.FILES['file']
        try:
            df = pd.read_excel(file)
            items = []
            
            for _, row in df.iterrows():
                if type == 'masuk':
                    # Validate SKU
                    sku = str(row.get('SKU', '')).strip()
                    medicine = Medicine.objects.filter(sku=sku).first()
                    items.append({
                        'sku': sku,
                        'name': row.get('Nama Barang', medicine.name if medicine else 'Unknown'),
                        'batch': str(row.get('Batch', '')),
                        'expiry': str(row.get('Expiry Date (YYYY-MM-DD)', '')),
                        'qty': int(row.get('Qty', 0)),
                        'buy': float(row.get('Harga Beli', 0)),
                        'sell': float(row.get('Harga Jual', 0)),
                        'valid': medicine is not None
                    })
                else:
                    sku = str(row.get('SKU', '')).strip()
                    batch_num = str(row.get('Batch Number', '')).strip()
                    medicine = Medicine.objects.filter(sku=sku).first()
                    batch = Batch.objects.filter(medicine=medicine, batch_number=batch_num).first() if medicine else None
                    items.append({
                        'sku': sku,
                        'batch': batch_num,
                        'qty': int(row.get('Qty', 0)),
                        'note': str(row.get('Catatan', '')),
                        'valid': batch is not None and batch.quantity >= int(row.get('Qty', 0))
                    })
            
            if type == 'masuk':
                request.session['import_cart'] = items
                request.session['cart_faktur_id'] = faktur_id
                return redirect('faktur_detail', pk=faktur_id)
            else:
                request.session['export_cart'] = items
                return redirect('barang_keluar')
                
        except Exception as e:
            messages.error(request, f"Gagal mengimpor file: {str(e)}")
            
    return redirect('home')

@login_required
def ocr_faktur(request, faktur_id):
    if request.method == 'POST' and request.FILES.get('image'):
        image_file = request.FILES['image']
        try:
            # Read image and encode to base64
            img_data = base64.b64encode(image_file.read()).decode('utf-8')
            
            prompt = """
            Extract items from this invoice image. Return a JSON object with a list 'items'.
            Each item should have: 'sku', 'name', 'batch', 'expiry' (YYYY-MM-DD), 'qty', 'buy', 'sell'.
            If SKU is not visible, leave it empty.
            Format the output strictly as JSON.
            """
            
            response = LocalAIApi.create_response({
                "model": "gpt-4o",
                "input": [
                    {
                        "role": "user",
                        "content": [
                            {"type": "text", "text": prompt},
                            {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img_data}"}}
                        ]
                    }
                ],
                "text": {"format": {"type": "json_object"}}
            })
            
            if response.get("success"):
                data = LocalAIApi.decode_json_from_response(response)
                items = data.get('items', [])
                
                # Enrich with validation
                for item in items:
                    sku = item.get('sku', '')
                    medicine = Medicine.objects.filter(sku=sku).first() if sku else None
                    item['valid'] = medicine is not None
                
                request.session['import_cart'] = items
                request.session['cart_faktur_id'] = faktur_id
                messages.success(request, "OCR Berhasil. Silakan periksa data di keranjang.")
            else:
                messages.error(request, f"Gagal OCR: {response.get('error')}")
                
        except Exception as e:
            messages.error(request, f"Error OCR: {str(e)}")
            
    return redirect('faktur_detail', pk=faktur_id)

@login_required
def process_cart(request, type, faktur_id=None):
    if type == 'masuk':
        cart = request.session.get('import_cart', [])
        faktur = get_object_or_404(Faktur, pk=faktur_id)
        
        count = 0
        for item in cart:
            if item.get('valid'):
                medicine = Medicine.objects.get(sku=item['sku'])
                batch = Batch.objects.create(
                    medicine=medicine,
                    faktur=faktur,
                    batch_number=item['batch'],
                    expiry_date=item['expiry'],
                    quantity=item['qty'],
                    buying_price=item['buy'],
                    selling_price=item['sell']
                )
                StockTransaction.objects.create(
                    medicine=medicine,
                    batch=batch,
                    faktur=faktur,
                    transaction_type='IN',
                    quantity=item['qty'],
                    note=f"Import Excel/OCR Faktur {faktur.faktur_number}"
                )
                count += 1
        
        del request.session['import_cart']
        del request.session['cart_faktur_id']
        messages.success(request, f"{count} barang berhasil diimpor.")
        return redirect('faktur_detail', pk=faktur_id)
    
    else:
        cart = request.session.get('export_cart', [])
        count = 0
        for item in cart:
            if item.get('valid'):
                medicine = Medicine.objects.get(sku=item['sku'])
                batch = Batch.objects.get(medicine=medicine, batch_number=item['batch'])
                qty = item['qty']
                
                batch.quantity -= qty
                batch.save()
                
                StockTransaction.objects.create(
                    medicine=medicine,
                    batch=batch,
                    transaction_type='OUT',
                    quantity=qty,
                    note=item.get('note', 'Import Excel')
                )
                count += 1
        
        del request.session['export_cart']
        messages.success(request, f"{count} barang keluar berhasil diproses.")
        return redirect('barang_keluar')

@login_required
def clear_cart(request, type, faktur_id=None):
    if type == 'masuk':
        if 'import_cart' in request.session:
            del request.session['import_cart']
        return redirect('faktur_detail', pk=faktur_id)
    else:
        if 'export_cart' in request.session:
            del request.session['export_cart']
        return redirect('barang_keluar')