import json
import io
import pandas as pd
import numpy as np
import base64
import matplotlib
matplotlib.use('Agg') # Wajib dipasang biar server nggak crash
import matplotlib.pyplot as plt
from django.template.loader import get_template
from xhtml2pdf import pisa
from sklearn.cluster import KMeans
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db import transaction
from django.http import HttpResponse
from django.core.paginator import Paginator
from .models import SupplyChainData

# ================================================================
# 1. AUTHENTICATION & DASHBOARD
# ================================================================

def login_view(request):
    if request.user.is_authenticated:
        return redirect('dashboard')
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            login(request, form.get_user())
            return redirect('dashboard')
        messages.error(request, "Username atau password salah.")
    else:
        form = AuthenticationForm()
    return render(request, 'analisis/login.html', {'form': form})

def logout_view(request):
    logout(request)
    return redirect('login')

@login_required
def dashboard_view(request):
    user_data = list(SupplyChainData.objects.filter(user=request.user))
    
    # ---------------------------------------------------------
    # 🧠 MACHINE LEARNING K-MEANS CORE ENGINE
    # ---------------------------------------------------------
    if len(user_data) >= 3:
        X = np.array([item.quantity for item in user_data]).reshape(-1, 1)
        kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
        labels = kmeans.fit_predict(X)
        centroids = kmeans.cluster_centers_.flatten()
        sorted_idx = np.argsort(centroids)
        
        label_mapping = {
            sorted_idx[0]: 'Dead Stock',
            sorted_idx[1]: 'Slow Moving',
            sorted_idx[2]: 'Fast Moving'
        }
        for i, item in enumerate(user_data):
            item.cluster_label = label_mapping[labels[i]]
    else:
        for item in user_data:
            item.cluster_label = 'Dead Stock'
            
    # --- PENGURUTAN TABEL REKAP (FAST -> SLOW -> DEAD) ---
    urutan_klaster = {'Fast Moving': 1, 'Slow Moving': 2, 'Dead Stock': 3}
    user_data.sort(key=lambda x: urutan_klaster.get(x.cluster_label, 4))
    # ----------------------------------------------------------

    fast_moving = sorted([i for i in user_data if i.cluster_label == 'Fast Moving'], key=lambda x: x.quantity, reverse=True)
    slow_moving = sorted([i for i in user_data if i.cluster_label == 'Slow Moving'], key=lambda x: x.quantity, reverse=True)
    dead_stock = sorted([i for i in user_data if i.cluster_label == 'Dead Stock'], key=lambda x: x.quantity)
    
    chart_labels_list = [p.product_name for p in fast_moving[:5]]
    chart_values_list = [float(p.quantity) for p in fast_moving[:5]]
    
    # --- DATA PROMO DUMMY BUAT DASHBOARD ---
    # Lu bisa ganti teksnya di sini sesuai kebutuhan presentasi skripsi
# --- DATA PROMO DUMMY BUAT DASHBOARD ---
    promo_list = [
        {'nama_barang': 'Pristine Botol 600ml (Dus)', 'periode': '01 Des - 31 Des', 'keterangan_diskon': 'Diskon 10%'},
        {'nama_barang': 'Aqua Botol 1500ml (Dus)', 'periode': '01 Des - 31 Des', 'keterangan_diskon': 'Diskon 10%'},
        {'nama_barang': 'Pristine Botol 400ml (Dus)', 'periode': '01 Des - 31 Des', 'keterangan_diskon': 'Diskon 10%'}
    ]
    # --------------------------------------------------------------------------------
    
    context = {
        'top_fast': fast_moving[:5],      
        'top_dead': dead_stock[:5],      
        'all_items': user_data,          
        
        'fast_count': len(fast_moving),
        'slow_count': len(slow_moving),
        'dead_count': len(dead_stock),
        'total_produk': len(user_data),
        'total_unit': sum(item.quantity for item in user_data),
        
        'chart_labels': json.dumps(chart_labels_list),
        'chart_values': json.dumps(chart_values_list),
        'promo_list': promo_list,
    }
    return render(request, 'analisis/dashboard.html', context)

# ================================================================
# 2. UPLOAD & PROCESSING (ETL ENGINE)
# ================================================================

@login_required
def upload_view(request):
    if request.method == 'POST':
        dataset = request.FILES.get('file_dataset')
        if not dataset:
            messages.error(request, "Silakan pilih file terlebih dahulu.")
            return redirect('upload')
            
        try:
            xls = pd.ExcelFile(dataset)
            
            # Fungsi Penyapu Ranjau (Cari Baris Judul)
            def get_clean_dataframe(sheet_name, keyword='Kode'):
                df_raw = pd.read_excel(xls, sheet_name)
                mask = df_raw.apply(lambda row: row.astype(str).str.contains(keyword, case=False, na=False).any(), axis=1)
                if mask.any():
                    idx = mask.idxmax()
                    df_clean = df_raw.iloc[idx + 1:].copy()
                    df_clean.columns = df_raw.iloc[idx].astype(str).str.strip()
                    df_clean = df_clean.loc[:, df_clean.columns != 'nan']
                    return df_clean
                df_raw.columns = df_raw.columns.astype(str).str.strip()
                return df_raw

            df_master = get_clean_dataframe('Master Produk', 'Kode')
            df_stok = get_clean_dataframe('Laporan Stok Gudang', 'Kode Barang')
            df_beli = get_clean_dataframe('Data Pembelian', 'Kode Barang')
            df_jual = get_clean_dataframe('Data Penjualan', 'Kode Barang')

            if 'Kode Produk' in df_master.columns:
                df_master = df_master.rename(columns={'Kode Produk': 'Kode Barang'})

            for df in [df_master, df_stok, df_beli, df_jual]:
                df.dropna(subset=['Kode Barang'], inplace=True)
                df['Kode Barang'] = df['Kode Barang'].astype(str).str.strip().str.upper()

            saldo_awal = df_stok.groupby('Kode Barang')['Stok Awal'].sum().reset_index()
            
            col_beli = 'Qty Masuk' if 'Qty Masuk' in df_beli.columns else 'Qty'
            col_jual = 'Qty Keluar' if 'Qty Keluar' in df_jual.columns else 'Qty'
            
            total_beli = df_beli.groupby('Kode Barang')[col_beli].sum().reset_index().rename(columns={col_beli: 'Total Beli'})
            jual_grouped = df_jual.groupby('Kode Barang').agg({
                col_jual: 'sum',
                'Nominal Transaksi': 'sum'
            }).reset_index().rename(columns={col_jual: 'Total Jual'})

            df_final = df_master[['Kode Barang', 'Nama Barang', 'Satuan']].copy()
            df_final = df_final.merge(saldo_awal, on='Kode Barang', how='left')
            df_final = df_final.merge(total_beli, on='Kode Barang', how='left')
            df_final = df_final.merge(jual_grouped, on='Kode Barang', how='left')

            df_final.fillna(0, inplace=True)
            df_final['Stok Akhir'] = df_final['Stok Awal'] + df_final['Total Beli'] - df_final['Total Jual']

            with transaction.atomic():
                SupplyChainData.objects.filter(user=request.user).delete()
                objs = []
                for _, row in df_final.iterrows():
                    stok_awal_val = int(row['Stok Awal']) if pd.notna(row['Stok Awal']) else 0
                    pembelian_val = int(row['Total Beli']) if pd.notna(row['Total Beli']) else 0
                    penjualan_val = int(row['Total Jual']) if pd.notna(row['Total Jual']) else 0
                    stok_akhir_val = int(row['Stok Akhir']) if pd.notna(row['Stok Akhir']) else 0
                    
                    objs.append(SupplyChainData(
                        user=request.user,
                        input_kode=str(row['Kode Barang'])[:50],
                        product_name=str(row['Nama Barang'])[:255],
                        category_name=str(row.get('Satuan', 'General'))[:100],
                        sales=float(row['Nominal Transaksi']) if pd.notna(row['Nominal Transaksi']) else 0,
                        quantity=penjualan_val, 
                        stok_awal=stok_awal_val,
                        pembelian=pembelian_val,
                        penjualan=penjualan_val,
                        stok_akhir=stok_akhir_val,
                        order_status='Completed'
                    ))
                SupplyChainData.objects.bulk_create(objs)

            messages.success(request, f"Sukses! {len(objs)} produk berhasil diimpor beserta mutasi stoknya.")
            return redirect('dashboard')

        except Exception as e:
            messages.error(request, f"Gagal memproses file: {str(e)}")
            return redirect('upload')

    return render(request, 'analisis/upload.html')

# ================================================================
# 3. INVENTORY LIST & DETAIL
# ================================================================

@login_required
def inventory_list_view(request):
    query = request.GET.get('q')
    all_data = list(SupplyChainData.objects.filter(user=request.user).order_by('-id'))
    
    if len(all_data) >= 3:
        X = np.array([item.quantity for item in all_data]).reshape(-1, 1)
        kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
        labels = kmeans.fit_predict(X)
        centroids = kmeans.cluster_centers_.flatten()
        sorted_idx = np.argsort(centroids)
        
        label_mapping = {
            sorted_idx[0]: 'Dead Stock',
            sorted_idx[1]: 'Slow Moving',
            sorted_idx[2]: 'Fast Moving'
        }
        for i, item in enumerate(all_data):
            item.cluster_label = label_mapping[labels[i]]
    else:
        for item in all_data:
            item.cluster_label = 'Dead Stock'
            
    # --- KODE FIX: Ngurutin dari Fast -> Slow -> Dead ---
    urutan_klaster = {'Fast Moving': 1, 'Slow Moving': 2, 'Dead Stock': 3}
    all_data.sort(key=lambda x: urutan_klaster.get(x.cluster_label, 4))
    # ----------------------------------------------------

    if query:
        filtered_data = [
            item for item in all_data
            if query.lower() in item.product_name.lower() or query.lower() in str(item.input_kode).lower()
        ]
    else:
        filtered_data = all_data

    paginator = Paginator(filtered_data, 10)
    page_obj = paginator.get_page(request.GET.get('page'))
    
    return render(request, 'analisis/inventory_list.html', {'page_obj': page_obj})

@login_required
def inventory_detail_view(request, item_id):
    all_data = list(SupplyChainData.objects.filter(user=request.user))
    item = get_object_or_404(SupplyChainData, id=item_id, user=request.user)
    
    if len(all_data) >= 3:
        X = np.array([i.quantity for i in all_data]).reshape(-1, 1)
        kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
        labels = kmeans.fit_predict(X)
        centroids = kmeans.cluster_centers_.flatten()
        sorted_idx = np.argsort(centroids)
        
        label_mapping = {
            sorted_idx[0]: 'Dead Stock',
            sorted_idx[1]: 'Slow Moving',
            sorted_idx[2]: 'Fast Moving'
        }
        for i, data_obj in enumerate(all_data):
            if data_obj.id == item.id:
                item.cluster_label = label_mapping[labels[i]]
                break
    else:
        item.cluster_label = 'Dead Stock'
        
    return render(request, 'analisis/inventory_detail.html', {'item': item})

# ================================================================
# 4. PDF EXPORT
# ================================================================

@login_required
def export_pdf_view(request):
    user_data = list(SupplyChainData.objects.filter(user=request.user).order_by('-quantity'))
    
    if len(user_data) >= 3:
        X = np.array([item.quantity for item in user_data]).reshape(-1, 1)
        kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
        labels = kmeans.fit_predict(X)
        centroids = kmeans.cluster_centers_.flatten()
        sorted_idx = np.argsort(centroids)
        
        label_mapping = {
            sorted_idx[0]: 'Dead Stock',
            sorted_idx[1]: 'Slow Moving',
            sorted_idx[2]: 'Fast Moving'
        }
        for i, item in enumerate(user_data):
            item.cluster_label = label_mapping[labels[i]]
    else:
        for item in user_data:
            item.cluster_label = 'Dead Stock'

    fast_items = sorted([i for i in user_data if i.cluster_label == 'Fast Moving'], key=lambda x: x.quantity, reverse=True)
    slow_items = sorted([i for i in user_data if i.cluster_label == 'Slow Moving'], key=lambda x: x.quantity, reverse=True)
    dead_items = sorted([i for i in user_data if i.cluster_label == 'Dead Stock'], key=lambda x: x.quantity)

    # -------------------------------------------------------------
    # 🎨 3A. GRAFIK PIE CHART (PROPORSI STATUS)
    # -------------------------------------------------------------
    sizes = [len(fast_items), len(slow_items), len(dead_items)]
    pie_labels = ['Fast Moving', 'Slow Moving', 'Dead Stock']
    pie_colors = ['#16a34a', '#f59e0b', '#dc2626']

    plt.figure(figsize=(5, 3.5))
    if sum(sizes) > 0:
        plt.pie(sizes, labels=pie_labels, colors=pie_colors, autopct='%1.1f%%', startangle=140, textprops={'fontsize': 9, 'weight': 'bold'})
        plt.title('Proporsi Status Inventory', fontsize=11, fontweight='bold')
    
    buf_pie = io.BytesIO()
    plt.savefig(buf_pie, format='png', bbox_inches='tight')
    plt.close()
    buf_pie.seek(0)
    pie_base64 = base64.b64encode(buf_pie.getvalue()).decode('utf-8')
    buf_pie.close()

    # -------------------------------------------------------------
    # 📊 3B. GRAFIK BAR CHART (RESTOCK VS TERJUAL)
    # -------------------------------------------------------------
    target_items = fast_items[:5] + dead_items[:5]
    bar_labels = [item.product_name[:15] + ('..' if len(item.product_name)>15 else '') for item in target_items]
    bar_terjual = [item.penjualan for item in target_items]
    bar_restock = [item.pembelian for item in target_items]

    x = np.arange(len(bar_labels))
    width = 0.35

    plt.figure(figsize=(9, 4))
    ax = plt.gca()
    ax.bar(x - width/2, bar_restock, width, label='Restock (Masuk)', color='#3b82f6')
    ax.bar(x + width/2, bar_terjual, width, label='Terjual (Keluar)', color='#f97316')

    ax.set_ylabel('Jumlah Unit', fontsize=9)
    ax.set_title('Komparasi Arus Barang (Top 5 Paling Laris vs Top 5 Paling Numpuk)', fontsize=11, fontweight='bold')
    ax.set_xticks(x)
    ax.set_xticklabels(bar_labels, rotation=45, ha="right", fontsize=8)
    ax.legend(fontsize=8)
    plt.tight_layout()

    buf_bar = io.BytesIO()
    plt.savefig(buf_bar, format='png', bbox_inches='tight')
    plt.close()
    buf_bar.seek(0)
    bar_base64 = base64.b64encode(buf_bar.getvalue()).decode('utf-8')
    buf_bar.close()

    context = {
        'user': request.user,
        'fast_items': fast_items,
        'slow_items': slow_items,
        'dead_items': dead_items,
        'pie_chart': pie_base64,
        'bar_chart': bar_base64,
    }

    template_path = 'analisis/pdf_report.html'
    template = get_template(template_path)
    html = template.render(context)
    
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="Laporan_KMeans_Inventory.pdf"'
    
    pisa_status = pisa.CreatePDF(html, dest=response)
    if pisa_status.err:
        return HttpResponse('We had some errors <pre>' + html + '</pre>')
    return response