<?php

namespace App\Http\Controllers\Product;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Product;
use App\Models\Category;
use App\Models\Brand;
use App\Models\Branch;
use App\Models\ProductStock;
use App\Models\ProductPrice;

class ProductController extends Controller
{
    public function __construct()
    {
        $this->middleware(['permission:products.index'])->only('index');
        $this->middleware(['permission:products.create'])->only('save');
        $this->middleware(['permission:products.edit'])->only('update');
        $this->middleware(['permission:products.delete'])->only('delete');
    }

    public function index()
    {
        $title = "product";
        $products = Product::with(['category', 'brand', 'productStocks', 'productPrices'])->orderBy('id', 'desc')->get();
        $categories = Category::orderBy('name', 'asc')->get();
        $brands = Brand::orderBy('name', 'asc')->get();
        $branches = Branch::orderBy('name', 'asc')->get();

        return view('product.product', compact('title','products', 'categories', 'brands', 'branches'));
    }

    public function save(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|unique:products',
            'category_id' => 'required|exists:categories,id',
            'brand_id' => 'required|exists:brands,id',
            'unit' => 'required',
            'min_stock' => 'required|numeric|min:0',
            'stocks' => 'nullable|array',
            'stocks.*.branch_id' => 'required|exists:branches,id',
            'stocks.*.quantity' => 'required|numeric|min:0',
            'prices' => 'nullable|array',
            'prices.*.branch_id' => 'required|exists:branches,id',
            'prices.*.purchase_price' => 'required|numeric|min:0',
            'prices.*.selling_price' => 'required|numeric|min:0',
        ]);

        // Validasi: Cabang di stok harus ada di harga, dan sebaliknya
        $stockBranchIds = [];
        $priceBranchIds = [];

        if ($request->has('stocks')) {
            foreach ($request->stocks as $stock) {
                $stockBranchIds[] = $stock['branch_id'];
            }
        }

        if ($request->has('prices')) {
            foreach ($request->prices as $price) {
                $priceBranchIds[] = $price['branch_id'];
            }
        }

        // Cari cabang yang ada di stok tapi tidak ada di harga
        $missingInPrice = array_diff($stockBranchIds, $priceBranchIds);
        if (!empty($missingInPrice)) {
            $branchNames = Branch::whereIn('id', $missingInPrice)->pluck('name')->toArray();
            return redirect()->back()
                ->withInput()
                ->with('error', 'Cabang berikut ada di Tab Stok Barang tapi tidak ada di Tab Harga Cabang: ' . implode(', ', $branchNames) . '. Silakan tambahkan harga untuk cabang tersebut.');
        }

        // Cari cabang yang ada di harga tapi tidak ada di stok
        $missingInStock = array_diff($priceBranchIds, $stockBranchIds);
        if (!empty($missingInStock)) {
            $branchNames = Branch::whereIn('id', $missingInStock)->pluck('name')->toArray();
            return redirect()->back()
                ->withInput()
                ->with('error', 'Cabang berikut ada di Tab Harga Cabang tapi tidak ada di Tab Stok Barang: ' . implode(', ', $branchNames) . '. Silakan tambahkan stok untuk cabang tersebut.');
        }

        // Generate unique barcode
        $barcode = $this->generateBarcode();

        $product = Product::create([
            'name' => $request->input('name'),
            'category_id' => $request->input('category_id'),
            'brand_id' => $request->input('brand_id'),
            'barcode' => $barcode,
            'unit' => $request->input('unit'),
            'min_stock' => $request->input('min_stock'),
            'description' => $request->input('description'),
        ]);

        if($product){
            // Simpan stok per cabang
            if ($request->has('stocks')) {
                foreach ($request->stocks as $stock) {
                    ProductStock::create([
                        'product_id' => $product->id,
                        'branch_id' => $stock['branch_id'],
                        'quantity' => $stock['quantity'],
                    ]);
                }
            }

            // Simpan harga per cabang
            if ($request->has('prices')) {
                foreach ($request->prices as $price) {
                    ProductPrice::create([
                        'product_id' => $product->id,
                        'branch_id' => $price['branch_id'],
                        'purchase_price' => $price['purchase_price'],
                        'selling_price' => $price['selling_price'],
                        'effective_date' => date('Y-m-d'), // Set otomatis hari ini
                    ]);
                }
            }

            //redirect dengan pesan sukses
            return redirect()->route('product')->with(['success' => 'Data Produk, Stok, dan Harga Berhasil Disimpan!']);
        }else{
            //redirect dengan pesan error
            return redirect()->route('product')->with(['error' => 'Data Gagal Disimpan!']);
        }
    }

    private function generateBarcode()
    {
        $length = 100; // total panjang karakter random (tanpa PRD + date)
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_-+=[]{}|;:,.<>?';
        $charactersLength = strlen($characters);

        do {
            $randomString = '';
            for ($i = 0; $i < $length; $i++) {
                $randomString .= $characters[random_int(0, $charactersLength - 1)];
            }

            // contoh hasil: PRD250110 + 50 random
            $barcode = 'PRD' . date('ymd') . $randomString;

        } while (Product::where('barcode', $barcode)->exists());

        return $barcode;
    }

    public function update(Request $request, Product $product)
    {
        $this->validate($request, [
            'name' => 'required|unique:products,name,'.$product->id,
            'category_id' => 'required|exists:categories,id',
            'brand_id' => 'required|exists:brands,id',
            'unit' => 'required',
            'min_stock' => 'required|numeric|min:0',
            'stocks' => 'nullable|array',
            'stocks.*.branch_id' => 'required|exists:branches,id',
            'stocks.*.quantity' => 'required|numeric|min:0',
            'prices' => 'nullable|array',
            'prices.*.branch_id' => 'required|exists:branches,id',
            'prices.*.purchase_price' => 'required|numeric|min:0',
            'prices.*.selling_price' => 'required|numeric|min:0',
        ]);

        // Validasi: Cabang di stok harus ada di harga, dan sebaliknya
        $stockBranchIds = [];
        $priceBranchIds = [];

        if ($request->has('stocks')) {
            foreach ($request->stocks as $stock) {
                $stockBranchIds[] = $stock['branch_id'];
            }
        }

        if ($request->has('prices')) {
            foreach ($request->prices as $price) {
                $priceBranchIds[] = $price['branch_id'];
            }
        }

        // Cari cabang yang ada di stok tapi tidak ada di harga
        $missingInPrice = array_diff($stockBranchIds, $priceBranchIds);
        if (!empty($missingInPrice)) {
            $branchNames = Branch::whereIn('id', $missingInPrice)->pluck('name')->toArray();
            return redirect()->back()
                ->withInput()
                ->with('error', 'Cabang berikut ada di Tab Stok Barang tapi tidak ada di Tab Harga Cabang: ' . implode(', ', $branchNames) . '. Silakan tambahkan harga untuk cabang tersebut.');
        }

        // Cari cabang yang ada di harga tapi tidak ada di stok
        $missingInStock = array_diff($priceBranchIds, $stockBranchIds);
        if (!empty($missingInStock)) {
            $branchNames = Branch::whereIn('id', $missingInStock)->pluck('name')->toArray();
            return redirect()->back()
                ->withInput()
                ->with('error', 'Cabang berikut ada di Tab Harga Cabang tapi tidak ada di Tab Stok Barang: ' . implode(', ', $branchNames) . '. Silakan tambahkan stok untuk cabang tersebut.');
        }

        $product = Product::findOrFail($product->id);
        $product->update([
            'name' => $request->input('name'),
            'category_id' => $request->input('category_id'),
            'brand_id' => $request->input('brand_id'),
            'unit' => $request->input('unit'),
            'min_stock' => $request->input('min_stock'),
            'description' => $request->input('description')
        ]);

        if($product){
            // Update atau create stok per cabang
            if ($request->has('stocks')) {
                // Collect branch IDs yang dikirim dari form
                $submittedStockBranchIds = [];

                foreach ($request->stocks as $stockData) {
                    $submittedStockBranchIds[] = $stockData['branch_id'];

                    if (isset($stockData['id'])) {
                        // Update stock yang sudah ada
                        $stock = ProductStock::find($stockData['id']);
                        if ($stock && $stock->product_id == $product->id) {
                            $stock->update([
                                'branch_id' => $stockData['branch_id'],
                                'quantity' => $stockData['quantity'],
                            ]);
                        }
                    } else {
                        // Create stock baru
                        ProductStock::create([
                            'product_id' => $product->id,
                            'branch_id' => $stockData['branch_id'],
                            'quantity' => $stockData['quantity'],
                        ]);
                    }
                }

                // Hapus stock yang tidak ada di form (yang di-remove user)
                ProductStock::where('product_id', $product->id)
                    ->whereNotIn('branch_id', $submittedStockBranchIds)
                    ->delete();
            }

            // Update atau create harga per cabang
            if ($request->has('prices')) {
                // Collect branch IDs yang dikirim dari form
                $submittedPriceBranchIds = [];

                foreach ($request->prices as $priceData) {
                    $submittedPriceBranchIds[] = $priceData['branch_id'];

                    if (isset($priceData['id'])) {
                        // Update price yang sudah ada
                        $price = ProductPrice::find($priceData['id']);
                        if ($price && $price->product_id == $product->id) {
                            $price->update([
                                'branch_id' => $priceData['branch_id'],
                                'purchase_price' => $priceData['purchase_price'],
                                'selling_price' => $priceData['selling_price'],
                                // effective_date tidak diupdate, tetap pakai yang lama
                            ]);
                        }
                    } else {
                        // Create price baru
                        ProductPrice::create([
                            'product_id' => $product->id,
                            'branch_id' => $priceData['branch_id'],
                            'purchase_price' => $priceData['purchase_price'],
                            'selling_price' => $priceData['selling_price'],
                            'effective_date' => date('Y-m-d'), // Set otomatis hari ini
                        ]);
                    }
                }

                // Hapus price yang tidak ada di form (yang di-remove user)
                ProductPrice::where('product_id', $product->id)
                    ->whereNotIn('branch_id', $submittedPriceBranchIds)
                    ->delete();
            }

            //redirect dengan pesan sukses
            return redirect()->route('product')->with(['success' => 'Data Produk, Stok, dan Harga Berhasil Diupdate!']);
        }else{
            //redirect dengan pesan error
            return redirect()->route('product')->with(['error' => 'Data Gagal Diupdate!']);
        }
    }

    public function delete(Product $product)
    {
        $product->delete();

        return redirect()->route('product')->with('success', 'Data Berhasil Dihapus');
    }

    public function show(Product $product)
    {
        $title = "product";

        // Load all relationships
        $product->load([
            'category',
            'brand',
            'productStocks.branch',
            'productPrices.branch'
        ]);

        // Calculate total stock across all branches
        $totalStock = $product->productStocks->sum('quantity');

        // Calculate stock value
        $stockValue = 0;
        foreach ($product->productStocks as $stock) {
            $price = $product->productPrices
                ->where('branch_id', $stock->branch_id)
                ->sortByDesc('effective_date')
                ->first();
            if ($price) {
                $stockValue += $stock->quantity * $price->purchase_price;
            }
        }

        return view('product.show', compact('title', 'product', 'totalStock', 'stockValue'));
    }

    /**
     * Download template Excel untuk import produk
     */
    public function downloadTemplate()
    {
        $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        // BARIS 1: JUDUL (Merged A1:K1)
        $sheet->setCellValue('A1', 'TEMPLATE IMPORT PRODUK');
        $sheet->mergeCells('A1:K1');
        $sheet->getStyle('A1')->applyFromArray([
            'font' => ['bold' => true, 'size' => 16, 'color' => ['rgb' => 'FFFFFF']],
            'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4']],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER],
        ]);
        $sheet->getRowDimension(1)->setRowHeight(30);

        // BARIS 2: KOSONG

        // BARIS 3-10: PETUNJUK PENGISIAN
        $sheet->setCellValue('A3', 'PETUNJUK PENGISIAN:');
        $sheet->getStyle('A3')->getFont()->setBold(true)->setSize(11);

        $sheet->setCellValue('A4', '1. Kolom dengan tanda (*) WAJIB diisi');
        $sheet->setCellValue('A5', '2. Nama Produk harus UNIK (tidak boleh duplikat dengan produk yang sudah ada)');
        $sheet->setCellValue('A6', '3. Kategori dan Merek harus SUDAH ADA di sistem (jika belum ada, tambahkan dulu di Master Data)');
        $sheet->setCellValue('A7', '4. Cabang harus SUDAH ADA di sistem');
        $sheet->setCellValue('A8', '5. Unit contoh: pcs, box, unit, pack, dll');
        $sheet->setCellValue('A9', '6. Untuk produk yang SAMA dengan cabang BERBEDA, gunakan baris terpisah (lihat contoh baris 13-14)');
        $sheet->setCellValue('A10', '7. Hapus baris contoh (baris 13-15) sebelum mengisi data Anda');

        $sheet->getStyle('A4:A10')->applyFromArray([
            'font' => ['italic' => true, 'size' => 9],
            'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => 'FFF2CC']],
        ]);

        // BARIS 11: KOSONG (Separator)

        // BARIS 12: HEADER KOLOM
        $headers = [
            'A12' => 'NO',
            'B12' => 'Nama Produk*',
            'C12' => 'Kategori*',
            'D12' => 'Merek*',
            'E12' => 'Unit*',
            'F12' => 'Stok Min*',
            'G12' => 'Deskripsi',
            'H12' => 'Cabang*',
            'I12' => 'Stok*',
            'J12' => 'Harga Beli*',
            'K12' => 'Harga Jual*',
        ];

        foreach ($headers as $cell => $value) {
            $sheet->setCellValue($cell, $value);
        }

        // Style header kolom
        $sheet->getStyle('A12:K12')->applyFromArray([
            'font' => ['bold' => true, 'size' => 11, 'color' => ['rgb' => 'FFFFFF']],
            'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4']],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER],
        ]);
        $sheet->getRowDimension(12)->setRowHeight(25);

        // BARIS 13-15: CONTOH DATA
        $exampleData = [
            [1, 'Samsung A54', 'Handphone', 'Samsung', 'pcs', 5, 'HP Samsung A54 RAM 8GB', 'Pusat', 10, 3500000, 4200000],
            [2, 'Samsung A54', 'Handphone', 'Samsung', 'pcs', 5, 'HP Samsung A54 RAM 8GB', 'Bekasi', 5, 3500000, 4200000],
            [3, 'iPhone 15 Pro', 'Handphone', 'Apple', 'pcs', 3, 'iPhone 15 Pro 256GB', 'Pusat', 8, 15000000, 17500000],
        ];

        $row = 13;
        foreach ($exampleData as $data) {
            $col = 'A';
            foreach ($data as $value) {
                $sheet->setCellValue($col . $row, $value);

                // Format angka untuk harga
                if ($col == 'J' || $col == 'K') {
                    $sheet->getStyle($col . $row)->getNumberFormat()
                        ->setFormatCode('#,##0');
                }

                $col++;
            }
            $row++;
        }

        // Background untuk contoh data
        $sheet->getStyle('A13:K15')->applyFromArray([
            'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => 'E7E6E6']],
        ]);

        // Set lebar kolom
        $sheet->getColumnDimension('A')->setWidth(5);   // NO
        $sheet->getColumnDimension('B')->setWidth(25);  // Nama Produk
        $sheet->getColumnDimension('C')->setWidth(15);  // Kategori
        $sheet->getColumnDimension('D')->setWidth(15);  // Merek
        $sheet->getColumnDimension('E')->setWidth(10);  // Unit
        $sheet->getColumnDimension('F')->setWidth(10);  // Stok Min
        $sheet->getColumnDimension('G')->setWidth(30);  // Deskripsi
        $sheet->getColumnDimension('H')->setWidth(15);  // Cabang
        $sheet->getColumnDimension('I')->setWidth(10);  // Stok
        $sheet->getColumnDimension('J')->setWidth(15);  // Harga Beli
        $sheet->getColumnDimension('K')->setWidth(15);  // Harga Jual

        // Border untuk tabel header dan contoh
        $sheet->getStyle('A12:K15')->applyFromArray([
            'borders' => [
                'allBorders' => [
                    'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                    'color' => ['rgb' => '000000'],
                ],
            ],
        ]);

        // Alignment untuk kolom angka
        $sheet->getStyle('A13:A15')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); // NO
        $sheet->getStyle('E13:F15')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); // Unit, Stok Min
        $sheet->getStyle('H13:I15')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); // Cabang, Stok
        $sheet->getStyle('J13:K15')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT); // Harga

        // Download
        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
        $filename = 'template_import_produk_' . date('Ymd_His') . '.xlsx';

        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $filename . '"');
        header('Cache-Control: max-age=0');

        $writer->save('php://output');
        exit;
    }

    /**
     * Import produk dari Excel
     */
    public function importExcel(Request $request)
    {
        $this->validate($request, [
            'excel_file' => 'required|mimes:xlsx,xls|max:2048',
        ]);

        try {
            $file = $request->file('excel_file');
            $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file->getPathname());
            $sheet = $spreadsheet->getActiveSheet();
            $rows = $sheet->toArray();

            // Cek apakah file kosong
            if (count($rows) < 13) {
                return redirect()->back()->with('error', 'File Excel kosong atau format tidak sesuai!');
            }

            $successCount = 0;
            $errorCount = 0;
            $errors = [];
            $processedProducts = []; // Track produk yang sudah diproses

            // Mulai dari baris 13 (index 12) - setelah header (baris 12) dan mulai dari contoh/data
            for ($i = 12; $i < count($rows); $i++) {
                $row = $rows[$i];

                // Skip jika baris kosong
                if (empty($row[1]) && empty($row[2]) && empty($row[3])) {
                    continue;
                }

                $rowNumber = $i + 1;
                // $row[0] = NO (skip, tidak digunakan)
                $productName = isset($row[1]) ? trim($row[1]) : '';
                $categoryName = isset($row[2]) ? trim($row[2]) : '';
                $brandName = isset($row[3]) ? trim($row[3]) : '';
                $unit = isset($row[4]) ? trim($row[4]) : '';
                $minStock = isset($row[5]) ? (int)$row[5] : 0;
                $description = isset($row[6]) ? trim($row[6]) : null;
                $branchName = isset($row[7]) ? trim($row[7]) : '';
                $stockQty = isset($row[8]) ? (int)$row[8] : 0;
                $purchasePrice = isset($row[9]) ? (float)$row[9] : 0;
                $sellingPrice = isset($row[10]) ? (float)$row[10] : 0;

                // Validasi data wajib
                if (empty($productName) || empty($categoryName) || empty($brandName) || empty($unit) || empty($branchName)) {
                    $errors[] = "Baris {$rowNumber}: Data tidak lengkap (ada kolom wajib yang kosong)";
                    $errorCount++;
                    continue;
                }

                // Cari kategori
                $category = Category::where('name', $categoryName)->first();
                if (!$category) {
                    $errors[] = "Baris {$rowNumber}: Kategori \"{$categoryName}\" tidak ditemukan";
                    $errorCount++;
                    continue;
                }

                // Cari brand
                $brand = Brand::where('name', $brandName)->first();
                if (!$brand) {
                    $errors[] = "Baris {$rowNumber}: Merek \"{$brandName}\" tidak ditemukan";
                    $errorCount++;
                    continue;
                }

                // Cari cabang
                $branch = Branch::where('name', $branchName)->first();
                if (!$branch) {
                    $errors[] = "Baris {$rowNumber}: Cabang \"{$branchName}\" tidak ditemukan";
                    $errorCount++;
                    continue;
                }

                // Cek atau buat produk
                $product = Product::where('name', $productName)->first();

                if (!$product) {
                    // Generate barcode
                    $barcode = $this->generateBarcode();

                    // Buat produk baru
                    $product = Product::create([
                        'name' => $productName,
                        'category_id' => $category->id,
                        'brand_id' => $brand->id,
                        'barcode' => $barcode,
                        'unit' => $unit,
                        'min_stock' => $minStock,
                        'description' => $description,
                    ]);

                    $processedProducts[$productName] = [
                        'product' => $product,
                        'branches' => []
                    ];
                } else {
                    // Produk sudah ada, gunakan yang existing
                    if (!isset($processedProducts[$productName])) {
                        $processedProducts[$productName] = [
                            'product' => $product,
                            'branches' => []
                        ];
                    }
                }

                // Cek apakah cabang ini sudah diproses untuk produk ini
                if (in_array($branch->id, $processedProducts[$productName]['branches'])) {
                    $errors[] = "Baris {$rowNumber}: Cabang \"{$branchName}\" duplikat untuk produk \"{$productName}\"";
                    $errorCount++;
                    continue;
                }

                // Tambahkan cabang ke tracking
                $processedProducts[$productName]['branches'][] = $branch->id;

                // Simpan atau update stok
                ProductStock::updateOrCreate(
                    [
                        'product_id' => $product->id,
                        'branch_id' => $branch->id,
                    ],
                    [
                        'quantity' => $stockQty,
                    ]
                );

                // Simpan atau update harga
                ProductPrice::updateOrCreate(
                    [
                        'product_id' => $product->id,
                        'branch_id' => $branch->id,
                    ],
                    [
                        'purchase_price' => $purchasePrice,
                        'selling_price' => $sellingPrice,
                        'effective_date' => date('Y-m-d'),
                    ]
                );

                $successCount++;
            }

            // Buat pesan hasil
            $message = "Import selesai! Berhasil: {$successCount} baris";
            if ($errorCount > 0) {
                $message .= ", Gagal: {$errorCount} baris";
            }

            if (!empty($errors)) {
                $errorList = array_slice($errors, 0, 10); // Tampilkan max 10 error

                // Format pesan dengan line breaks yang proper
                $fullMessage = $message . "\n\nDetail Error:\n";
                foreach ($errorList as $error) {
                    $fullMessage .= "• " . $error . "\n";
                }

                if (count($errors) > 10) {
                    $fullMessage .= "... dan " . (count($errors) - 10) . ' error lainnya';
                }

                return redirect()->back()->with('warning', $fullMessage);
            }

            return redirect()->route('product')->with('success', $message);

        } catch (\Exception $e) {
            return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
        }
    }

}
