<?php
class ProductController {
    public function index(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();

        try {
            $page       = (int)($_GET['page'] ?? 1) ?: 1;
            $search     = trim($_GET['search'] ?? '');
            $catId      = (int)($_GET['category_id'] ?? 0);
            $brandId    = (int)($_GET['brand_id'] ?? 0);
            $status     = $_GET['status'] ?? '';
            $locationId = (int)($_GET['location_id'] ?? 0);

            error_log("Product index params: page=$page, search=[$search], catId=$catId, brandId=$brandId, status=[$status], locationId=$locationId");

            $products   = Product::listPaginated($page, $search, $catId ?: null, $brandId ?: null, $status, $locationId ?: null);
            $categories = Category::active();
            $brands     = Brand::active();
            $locations  = Location::active();

            $pageTitle = 'Products';
            ob_start();
            include APP_ROOT . '/views/tenant/products/index.php';
            $content = ob_get_clean();
            include APP_ROOT . '/views/tenant/layouts/main.php';
        } catch (Exception $e) {
            error_log("Product index error: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            flash('error', 'Error loading products: ' . $e->getMessage());
            redirectBack();
        }
    }

    public function create(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        PlanGuard::enforce('products');

        $categories = Category::active();
        $brands     = Brand::active();
        $locations  = Location::active();

        $pageTitle = 'Add Product';
        ob_start();
        include APP_ROOT . '/views/tenant/products/create.php';
        $content = ob_get_clean();
        include APP_ROOT . '/views/tenant/layouts/main.php';
    }

    public function store(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        Security::checkCsrf();
        PlanGuard::enforce('products');

        $data = [
            'name'            => Security::sanitize($_POST['name'] ?? ''),
            'sku'             => Security::sanitize($_POST['sku'] ?? ''),
            'barcode'         => Security::sanitize($_POST['barcode'] ?? ''),
            'category_id'     => (int)($_POST['category_id'] ?? 0) ?: null,
            'brand_id'        => (int)($_POST['brand_id'] ?? 0) ?: null,
            'cost_price'      => (float)($_POST['cost_price'] ?? 0),
            'selling_price'   => (float)($_POST['selling_price'] ?? 0),
            'wholesale_price' => (float)($_POST['wholesale_price'] ?? 0),
            'unit'            => Security::sanitize($_POST['unit'] ?? 'piece'),
            'wholesale_unit'  => Security::sanitize($_POST['wholesale_unit'] ?? ''),
            'wholesale_qty'   => (int)($_POST['wholesale_qty'] ?? 1),
            'alert_qty'       => (int)($_POST['alert_qty'] ?? 5),
            'batch_tracking'  => empty($_POST['batch_tracking']) ? 0 : 1,
            'serial_tracking' => empty($_POST['serial_tracking']) ? 0 : 1,
            'description'     => Security::sanitize($_POST['description'] ?? ''),
            'created_by'      => Auth::userId(),
        ];

        // Handle Image Upload
        if (!empty($_FILES['image']['tmp_name'])) {
            $ext  = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
            $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'];

            if (!in_array($ext, $allowedTypes)) {
                flash('error', 'Image must be a JPG, PNG, GIF, or WebP file');
                redirectBack();
                return;
            }

            // Validate file is actually an image
            $imageInfo = @getimagesize($_FILES['image']['tmp_name']);
            if ($imageInfo === false) {
                flash('error', 'Invalid image file');
                redirectBack();
                return;
            }

            // Check file size (max 5MB)
            if ($_FILES['image']['size'] > MAX_UPLOAD_SIZE) {
                flash('error', 'Image file must be less than 5MB');
                redirectBack();
                return;
            }

            $name = 'prod_' . bin2hex(random_bytes(8)) . '.' . $ext;
            $dir  = UPLOAD_PATH . '/' . Auth::tenantId();
            if (!is_dir($dir)) mkdir($dir, 0755, true);
            if (move_uploaded_file($_FILES['image']['tmp_name'], $dir . '/' . $name)) {
                $data['image'] = $name;
            }
        }

        // Capture initial stock and location before creating product
        $initialStock = (float)($_POST['initial_stock'] ?? 0);
        $locationId = (int)($_POST['location_id'] ?? 0);

        try {
            Product::create($data);
            $productId = db()->lastInsertId();

            // Add initial stock if provided
            if ($initialStock > 0 && $locationId > 0) {
                try {
                    adjustStock($productId, $locationId, $initialStock, null, Auth::tenantId());
                    logMovement($productId, $locationId, 'purchase', $initialStock, 'Initial stock');
                } catch (PDOException $stockError) {
                    // Log stock error but don't fail the product creation
                    error_log("Initial stock error for product '$productId': " . $stockError->getMessage());
                }
            }

            flash('success', 'Product created successfully');
            redirect('products');
        } catch (PDOException $e) {
            flash('error', 'Error creating product. SKU must be unique.');
            redirectBack();
        }
    }

    public function edit(string $id): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        $id = (int)$id;

        $product = Product::find($id);
        if (!$product) { flash('error', 'Product not found'); redirect('products'); }

        $categories = Category::active();
        $brands     = Brand::active();

        $pageTitle = 'Edit Product';
        ob_start();
        include APP_ROOT . '/views/tenant/products/edit.php';
        $content = ob_get_clean();
        include APP_ROOT . '/views/tenant/layouts/main.php';
    }

    public function update(string $id): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        Security::checkCsrf();
        $id = (int)$id;

        $product = Product::find($id);
        if (!$product) { flash('error','Product not found'); redirect('products'); }

        $data = [
            'name'            => Security::sanitize($_POST['name'] ?? ''),
            'sku'             => Security::sanitize($_POST['sku'] ?? ''),
            'barcode'         => Security::sanitize($_POST['barcode'] ?? ''),
            'category_id'     => (int)($_POST['category_id'] ?? 0) ?: null,
            'brand_id'        => (int)($_POST['brand_id'] ?? 0) ?: null,
            'cost_price'      => (float)($_POST['cost_price'] ?? 0),
            'selling_price'   => (float)($_POST['selling_price'] ?? 0),
            'wholesale_price' => (float)($_POST['wholesale_price'] ?? 0),
            'unit'            => Security::sanitize($_POST['unit'] ?? 'piece'),
            'wholesale_unit'  => Security::sanitize($_POST['wholesale_unit'] ?? ''),
            'wholesale_qty'   => (int)($_POST['wholesale_qty'] ?? 1),
            'alert_qty'       => (int)($_POST['alert_qty'] ?? 5),
            'batch_tracking'  => empty($_POST['batch_tracking']) ? 0 : 1,
            'serial_tracking' => empty($_POST['serial_tracking']) ? 0 : 1,
            'description'     => Security::sanitize($_POST['description'] ?? ''),
        ];

        if (!empty($_FILES['image']['tmp_name'])) {
            $ext  = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
            $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
            
            if (!in_array($ext, $allowedTypes)) {
                flash('error', 'Image must be a JPG, PNG, GIF, or WebP file');
                redirectBack();
                return;
            }
            
            // Validate file is actually an image
            $imageInfo = @getimagesize($_FILES['image']['tmp_name']);
            if ($imageInfo === false) {
                flash('error', 'Invalid image file');
                redirectBack();
                return;
            }
            
            // Check file size (max 5MB)
            if ($_FILES['image']['size'] > MAX_UPLOAD_SIZE) {
                flash('error', 'Image file must be less than 5MB');
                redirectBack();
                return;
            }
            
            $name = 'prod_' . bin2hex(random_bytes(8)) . '.' . $ext;
            $dir  = UPLOAD_PATH . '/' . Auth::tenantId();
            if (!is_dir($dir)) mkdir($dir, 0755, true);
            if (move_uploaded_file($_FILES['image']['tmp_name'], $dir . '/' . $name)) {
                $data['image'] = $name;
                // Delete old image
                if ($product->image) {
                    unlink($dir . '/' . $product->image);
                }
            }
        }

        try {
            Product::update($id, $data);
            flash('success', 'Product updated successfully');
            redirect('products');
        } catch (PDOException $e) {
            flash('error', 'Error updating product. Ensure SKU is unique.');
            redirectBack();
        }
    }

    public function show(string $id): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        $id = (int)$id;

        $product = Product::withStock($id);
        if (!$product) { flash('error','Product not found'); redirect('products'); }

        $pageTitle = e($product['name']);
        ob_start();
        include APP_ROOT . '/views/tenant/products/show.php';
        $content = ob_get_clean();
        include APP_ROOT . '/views/tenant/layouts/main.php';
    }

    public function history(string $id): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        $id = (int)$id;

        $product = Product::find($id);
        if (!$product) { flash('error','Product not found'); redirect('products'); }

        $movementSummary = Product::getMovementSummary($id);
        $movementSummaryByLocation = Product::getMovementSummaryByLocation($id);
        $movementHistory = Product::getMovementHistory($id, 50); // Get last 50 movements

        $pageTitle = e($product['name']) . ' - History';
        ob_start();
        include APP_ROOT . '/views/tenant/products/history.php';
        $content = ob_get_clean();
        include APP_ROOT . '/views/tenant/layouts/main.php';
    }

    public function destroy(string $id): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        Security::checkCsrf();
        Auth::requireRole(['admin','owner','manager']);

        $id = (int)$id;
        if (Product::delete($id)) {
            flash('success', 'Product deleted');
        } else {
            flash('error', 'Unable to delete product');
        }
        redirect('products');
    }

    public function import(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        Security::checkCsrf();
        PlanGuard::enforce('products');

        if (empty($_FILES['csv_file']['tmp_name'])) {
            flash('error', 'Please select a CSV file to import');
            redirect('products/create');
        }

        $file = $_FILES['csv_file'];
        $locationId = (int)($_POST['location_id'] ?? 0);
        $skipDuplicates = !empty($_POST['skip_duplicates']);

        if ($locationId === 0) {
            flash('error', 'Please select a location for the imported products');
            redirect('products/create');
        }

        // Validate file
        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if ($ext !== 'csv') {
            flash('error', 'Only CSV files are allowed');
            redirect('products/create');
        }

        // Count rows to enforce plan limits
        $rowCount = 0;
        if (($handle = fopen($file['tmp_name'], "r")) !== FALSE) {
            while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
                $rowCount++;
            }
            fclose($handle);
        }
        $productCount = $rowCount - 1; // Subtract header
        if ($productCount > 0) {
            PlanGuard::enforce('products', $productCount);
        }

        // Parse CSV
        $handle = fopen($file['tmp_name'], 'r');
        if (!$handle) {
            flash('error', 'Unable to open CSV file');
            redirect('products/create');
        }

        $header = fgetcsv($handle);
        // Normalize header to lowercase for case-insensitive matching
        $header = array_map(function($col) {
            return strtolower(trim($col));
        }, $header);
        $expectedColumns = ['name', 'sku', 'barcode', 'category', 'brand', 'cost_price', 'selling_price', 'unit', 'alert_qty', 'description'];

        // Validate header (case-insensitive)
        $missingColumns = array_diff($expectedColumns, $header);
        if (!empty($missingColumns)) {
            flash('error', 'CSV is missing required columns: ' . implode(', ', $missingColumns));
            fclose($handle);
            redirect('products/create');
        }

        $successCount = 0;
        $skipCount = 0;
        $errorCount = 0;
        $errors = [];

        $rowNumber = 1;
        while (($row = fgetcsv($handle)) !== false) {
            $rowNumber++;
            
            if (empty($row[0])) { // Skip empty rows
                continue;
            }

            $data = array_combine($header, $row);
            // Trim all data values
            $data = array_map(function($val) {
                return is_string($val) ? trim($val) : $val;
            }, $data);

            // Check for duplicate SKU
            if ($skipDuplicates) {
                $existing = db()->prepare("SELECT id FROM products WHERE tenant_id = ? AND sku = ?");
                $existing->execute([Auth::tenantId(), $data['sku']]);
                if ($existing->fetch()) {
                    $skipCount++;
                    continue;
                }
            }

            // Find or create category
            $categoryId = null;
            if (!empty($data['category'])) {
                $cat = db()->prepare("SELECT id FROM categories WHERE tenant_id = ? AND name = ?");
                $cat->execute([Auth::tenantId(), trim($data['category'])]);
                $catResult = $cat->fetch();
                if ($catResult) {
                    $categoryId = $catResult['id'];
                } else {
                    // Create category
                    $newCat = db()->prepare("INSERT INTO categories (tenant_id, name, created_at) VALUES (?, ?, NOW())");
                    $newCat->execute([Auth::tenantId(), trim($data['category'])]);
                    $categoryId = db()->lastInsertId();
                }
            }

            // Find or create brand
            $brandId = null;
            if (!empty($data['brand'])) {
                $brand = db()->prepare("SELECT id FROM brands WHERE tenant_id = ? AND name = ?");
                $brand->execute([Auth::tenantId(), trim($data['brand'])]);
                $brandResult = $brand->fetch();
                if ($brandResult) {
                    $brandId = $brandResult['id'];
                } else {
                    // Create brand
                    $newBrand = db()->prepare("INSERT INTO brands (tenant_id, name, created_at) VALUES (?, ?, NOW())");
                    $newBrand->execute([Auth::tenantId(), trim($data['brand'])]);
                    $brandId = db()->lastInsertId();
                }
            }

            // Find or create unit
            $unitName = trim($data['unit'] ?? 'piece');
            if (!empty($unitName)) {
                $unit = db()->prepare("SELECT id, name FROM units WHERE tenant_id = ? AND name = ?");
                $unit->execute([Auth::tenantId(), $unitName]);
                $unitResult = $unit->fetch();
                if ($unitResult) {
                    // Use existing unit name (normalized)
                    $unitName = $unitResult['name'];
                } else {
                    // Create unit
                    $newUnit = db()->prepare("INSERT INTO units (tenant_id, name, abbreviation, is_active, created_at) VALUES (?, ?, ?, 1, NOW())");
                    // Generate abbreviation from name (first 3 chars or full name if shorter)
                    $abbreviation = strlen($unitName) > 3 ? substr($unitName, 0, 3) : $unitName;
                    $newUnit->execute([Auth::tenantId(), $unitName, $abbreviation]);
                }
            }

            // Prepare product data
            $productData = [
                'name' => Security::sanitize($data['name']),
                'sku' => Security::sanitize($data['sku']),
                'barcode' => Security::sanitize($data['barcode'] ?? ''),
                'category_id' => $categoryId,
                'brand_id' => $brandId,
                'cost_price' => (float)($data['cost_price'] ?? 0),
                'selling_price' => (float)($data['selling_price'] ?? 0),
                'unit' => Security::sanitize($data['unit'] ?? 'piece'),
                'alert_qty' => (int)($data['alert_qty'] ?? 5),
                'description' => Security::sanitize($data['description'] ?? ''),
                'batch_tracking' => 0,
                'serial_tracking' => 0,
                'created_by' => Auth::userId(),
            ];

            try {
                Product::create($productData);
                $successCount++;

                // Add initial stock to location if quantity is provided
                $initialStock = isset($data['initial_stock']) ? $data['initial_stock'] : 0;
                error_log("Product import: Checking initial_stock for '{$data['name']}' - value: '$initialStock', isset: " . (isset($data['initial_stock']) ? 'yes' : 'no') . ", empty: " . (empty($initialStock) ? 'yes' : 'no') . ", >0: " . ($initialStock > 0 ? 'yes' : 'no'));
                error_log("Product import: All data keys: " . print_r(array_keys($data), true));
                if (!empty($initialStock) && $initialStock > 0) {
                    $productId = db()->lastInsertId();
                    $quantity = (float)$initialStock;
                    error_log("Product import: Adding stock for product '$productId', location '$locationId', qty: $quantity");

                    try {
                        // Just rely on adjustStock, which handles insertion and increments properly!
                        adjustStock($productId, $locationId, $quantity, null, Auth::tenantId());
                        logMovement($productId, $locationId, 'purchase', $quantity, '');

                    } catch (PDOException $stockError) {
                        // Log stock error but don't fail the product import
                        error_log("Product import: Stock error for '{$data['name']}': " . $stockError->getMessage());
                        $errors[] = "Row $rowNumber: Stock import failed for product '{$data['name']}' - " . $stockError->getMessage();
                    }
                }

            } catch (PDOException $e) {
                $errorCount++;
                $errors[] = "Row $rowNumber: " . $e->getMessage();
            }
        }

        fclose($handle);

        // Show result
        $message = "Import complete: $successCount products imported successfully";
        if ($skipCount > 0) {
            $message .= ", $skipCount skipped (duplicates)";
        }
        if ($errorCount > 0) {
            $message .= ", $errorCount errors";
            flash('warning', $message . '. Check logs for details.');
        } else {
            flash('success', $message);
        }

        redirect('products');
    }

    public function importTemplate(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();

        $template = "name,sku,barcode,category,brand,cost_price,selling_price,unit,alert_qty,description,initial_stock\n";
        $template .= "Sample Product,SKU-001,BAR-001,Electronics,Brand X,10.00,15.00,piece,5,Sample description,10\n";
        $template .= "Another Product,SKU-002,BAR-002,Electronics,Brand Y,20.00,30.00,box,2,Another description,5\n";

        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="products_import_template.csv"');
        header('Content-Length: ' . strlen($template));
        echo $template;
        exit;
    }

    public function stockImport(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();
        Security::checkCsrf();

        // Debug logging
        error_log("Stock import started. FILES: " . print_r($_FILES, true) . " POST: " . print_r($_POST, true));

        if (empty($_FILES['csv_file']['tmp_name'])) {
            error_log("Stock import: No file uploaded");
            flash('error', 'Please select a CSV file to import');
            redirect('products');
        }

        $file = $_FILES['csv_file'];
        $replaceStock = !empty($_POST['replace_stock']);

        // Validate file
        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if ($ext !== 'csv') {
            flash('error', 'Only CSV files are allowed');
            redirect('products');
        }

        if ($file['size'] > 5 * 1024 * 1024) { // 5MB limit
            flash('error', 'File size exceeds 5MB limit');
            redirect('products');
        }

        // Parse CSV
        $handle = fopen($file['tmp_name'], 'r');
        if (!$handle) {
            flash('error', 'Unable to open CSV file');
            redirect('products');
        }

        $header = fgetcsv($handle);
        // Normalize header: trim whitespace and convert to lowercase
        $header = array_map(function($col) {
            return strtolower(trim($col));
        }, $header);

        // Check for stock format (sku, location_name, quantity) OR product format (sku, initial_stock)
        $hasStockFormat = in_array('sku', $header) && in_array('location_name', $header) && in_array('quantity', $header);
        $hasProductFormat = in_array('sku', $header) && in_array('initial_stock', $header);

        error_log("Stock import: Header: " . print_r($header, true) . " hasStockFormat=$hasStockFormat, hasProductFormat=$hasProductFormat");

        if (!$hasStockFormat && !$hasProductFormat) {
            error_log("Stock import: Invalid CSV format");
            flash('error', 'CSV must have either: (sku, location_name, quantity) for stock import OR (sku, initial_stock) for product import. Found: ' . implode(', ', $header));
            fclose($handle);
            redirect('products');
        }

        $isProductFormat = $hasProductFormat && !$hasStockFormat;
        $defaultLocationId = $isProductFormat ? (int)($_POST['default_location'] ?? 0) : 0;

        error_log("Stock import: isProductFormat=$isProductFormat, defaultLocationId=$defaultLocationId");

        if ($isProductFormat && $defaultLocationId === 0) {
            error_log("Stock import: No default location selected");
            flash('error', 'Please select a default location for product format import');
            fclose($handle);
            redirect('products');
        }

        $successCount = 0;
        $errorCount = 0;
        $errors = [];

        $rowNumber = 1;
        while (($row = fgetcsv($handle)) !== false) {
            $rowNumber++;

            if (empty($row[0])) { // Skip empty rows
                continue;
            }

            $data = array_combine($header, $row);

            // Map based on format
            if ($isProductFormat) {
                $data = [
                    'sku' => $data['sku'] ?? '',
                    'quantity' => $data['initial_stock'] ?? 0,
                ];
            } else {
                $data = [
                    'sku' => $data['sku'] ?? '',
                    'location_name' => $data['location_name'] ?? '',
                    'quantity' => $data['quantity'] ?? 0,
                ];
            }

            // Find product by SKU
            $product = db()->prepare("SELECT id, name FROM products WHERE tenant_id = ? AND sku = ?");
            $product->execute([Auth::tenantId(), trim($data['sku'])]);
            $productResult = $product->fetch();

            if (!$productResult) {
                $errorCount++;
                $errors[] = "Row $rowNumber: Product with SKU '{$data['sku']}' not found";
                continue;
            }

            // Find location
            if ($isProductFormat) {
                $locationId = $defaultLocationId;
            } else {
                $location = db()->prepare("SELECT id FROM locations WHERE tenant_id = ? AND name = ?");
                $location->execute([Auth::tenantId(), trim($data['location_name'])]);
                $locationResult = $location->fetch();

                if (!$locationResult) {
                    $errorCount++;
                    $errors[] = "Row $rowNumber: Location '{$data['location_name']}' not found";
                    continue;
                }
                $locationId = $locationResult['id'];
            }

            $productId = $productResult['id'];
            $quantity = (float)($data['quantity'] ?? 0);

            try {
                // Determine existing stock first
                $existingStockQuery = db()->prepare("SELECT quantity FROM stock WHERE tenant_id = ? AND product_id = ? AND location_id = ? AND batch_id IS NULL");
                $existingStockQuery->execute([Auth::tenantId(), $productId, $locationId]);
                $existing = $existingStockQuery->fetchColumn();
                $existingQty = $existing ? (float)$existing : 0;

                if ($replaceStock) {
                    $qtyToAdjust = $quantity - $existingQty;
                    $movementType = 'adjustment';
                } else {
                    $qtyToAdjust = $quantity;
                    $movementType = 'purchase';
                }

                if ($qtyToAdjust != 0) {
                    adjustStock($productId, $locationId, $qtyToAdjust, null, Auth::tenantId());
                    logMovement($productId, $locationId, $movementType, $qtyToAdjust, '');
                }

                $successCount++;

            } catch (PDOException $e) {
                $errorCount++;
                $errors[] = "Row $rowNumber: " . $e->getMessage();
            }
        }

        fclose($handle);

        // Show result
        $message = "Stock import complete: $successCount products updated successfully";
        error_log("Stock import: $message, errors: " . print_r($errors, true));
        if ($errorCount > 0) {
            $message .= ", $errorCount errors";
            flash('warning', $message . '. Check logs for details.');
        } else {
            flash('success', $message);
        }

        redirect('products');
    }

    public function stockImportTemplate(): void {
        Auth::requireLogin();
        Auth::requireActiveTenant();

        // Get active locations for template
        $locations = Location::active();

        $template = "sku,location_name,quantity\n";
        foreach ($locations as $loc) {
            $template .= "SKU-001,{$loc['name']},50\n";
        }

        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="stock_import_template.csv"');
        header('Content-Length: ' . strlen($template));
        echo $template;
        exit;
    }
}
