<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Core\Response;
use App\Models\InventoryModel;
use PDO;

class InventoryController extends Controller
{
    private InventoryModel $inventoryModel;

    public function __construct()
    {
        $this->inventoryModel = new InventoryModel();
    }

    public function index(): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $user = $_REQUEST['user'];
        $role = $user['role'] ?? 'Staff';
        $userId = (int) $user['sub'];
        
        $filters = [
            'search' => $_GET['search'] ?? null,
            'category_id' => isset($_GET['category_id']) && $_GET['category_id'] !== '' ? (int) $_GET['category_id'] : null,
            'warehouse_id' => isset($_GET['warehouse_id']) && $_GET['warehouse_id'] !== '' ? (int) $_GET['warehouse_id'] : null,
            'low_stock' => isset($_GET['low_stock']) ? (int) $_GET['low_stock'] : null,
        ];

        // RBAC: Restrict stock view to assigned warehouses if not Admin/Super Admin
        $assignedWh = $this->getAssignedWarehouseIds($tenantId, $userId);
        if (empty($assignedWh)) {
            // Return empty if no assignments
            Response::success(['data' => [], 'pagination' => ['total_records' => 0, 'total_pages' => 0]]);
        }
        if ($filters['warehouse_id']) {
            if (!in_array($filters['warehouse_id'], $assignedWh)) {
                Response::error('Access Denied: You are not assigned to this warehouse', [], 403);
            }
        } else {
            $filters['assigned_warehouses'] = $assignedWh;
        }

        $page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
        $perPage = isset($_GET['per_page']) ? max(1, (int) $_GET['per_page']) : 10;

        $summary = $this->inventoryModel->getStockSummary($tenantId, $filters, $page, $perPage);
        $total = $this->inventoryModel->countStockSummary($tenantId, $filters);

        Response::success([
            'data' => $summary,
            'pagination' => [
                'current_page' => $page,
                'per_page' => $perPage,
                'total_records' => $total,
                'total_pages' => ceil($total / $perPage)
            ]
        ]);
    }

    public function valuation(): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $user = $_REQUEST['user'];
        $role = $user['role'] ?? 'Staff';
        $userId = (int) $user['sub'];
        
        $this->requirePermission('inventory.view');

        $filters = [];
        // Even with permission, non-admins only see assigned warehouses
        if ($role !== 'Admin') {
            $assignedWh = $this->getAssignedWarehouseIds($tenantId, $userId);
            if (empty($assignedWh)) {
                Response::success([
                    'total_valuation' => 0,
                    'active_skus' => 0,
                    'low_stock' => 0,
                    'out_of_stock' => 0
                ]);
            }
            $filters['assigned_warehouses'] = $assignedWh;
        }

        $valuation = $this->inventoryModel->getValuation($tenantId, $filters);
        Response::success($valuation);
    }

    public function adjust(): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $user = $_REQUEST['user'];
        $role = $user['role'] ?? 'Staff';
        $userId = (int) $user['sub'];
        $data = $this->getJsonBody();

        $this->requirePermission('inventory.adjust');

        if (empty($data['items']))
            Response::error('No items provided for adjustment');

        // RBAC: Check warehouse access
        if ($role !== 'Admin') {
            $assignedWh = $this->getAssignedWarehouseIds($tenantId, $userId);
            foreach ($data['items'] as $item) {
                if (!in_array((int)$item['warehouse_id'], $assignedWh)) {
                    Response::error('Access Denied: You are not assigned to warehouse ID ' . $item['warehouse_id'], [], 403);
                }
            }
        }

        try {
            $id = $this->inventoryModel->recordAdjustment($tenantId, $data, $data['items'], $userId);
            Response::success(['id' => $id], 'Stock adjusted successfully');
        } catch (\Exception $e) {
            Response::error($e->getMessage());
        }
    }

    public function transfer(): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $user = $_REQUEST['user'];
        $role = $user['role'] ?? 'Staff';
        $userId = (int) $user['sub'];
        $data = $this->getJsonBody();

        $this->requirePermission('inventory.transfer');

        $this->validate($data, [
            'product_id' => 'required',
            'from_warehouse_id' => 'required',
            'to_warehouse_id' => 'required',
            'quantity' => 'required|numeric'
        ]);

        // RBAC: Check warehouse access
        if ($role !== 'Admin') {
            $assignedWh = $this->getAssignedWarehouseIds($tenantId, $userId);
            if (!in_array((int)$data['from_warehouse_id'], $assignedWh)) {
                Response::error('Access Denied: You are not assigned to the source warehouse', [], 403);
            }
            if (!in_array((int)$data['to_warehouse_id'], $assignedWh)) {
                Response::error('Access Denied: You are not assigned to the destination warehouse', [], 403);
            }
        }

        try {
            $this->inventoryModel->transferStock(
                $tenantId,
                (int) $data['product_id'],
                (int) $data['from_warehouse_id'],
                (int) $data['to_warehouse_id'],
                (float) $data['quantity'],
                $userId,
                $data['notes'] ?? null
            );
            Response::success([], 'Stock transferred successfully');
        } catch (\Exception $e) {
            Response::error($e->getMessage());
        }
    }

    public function getWarehouses(): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $user = $_REQUEST['user'];
        $role = $user['role'] ?? 'Staff';
        $userId = (int) $user['sub'];
        
        $search = $_GET['search'] ?? null;
        $db = $this->inventoryModel->getDb();
        
        $activeQuery = "status = 'active'";
        $params = [$tenantId];

        if (in_array($role, ['Admin', 'Super Admin'])) {
            $sql = "SELECT * FROM warehouses WHERE tenant_id = ? AND $activeQuery";
        } else {
            $sql = "SELECT w.* FROM warehouses w 
                    INNER JOIN user_warehouses uw ON w.id = uw.warehouse_id 
                    WHERE w.tenant_id = ? AND uw.user_id = ? AND w.$activeQuery";
            $params[] = $userId;
        }

        if ($search) {
            $sql .= " AND (w.name LIKE ? OR w.address LIKE ? OR w.city LIKE ?)";
            $params[] = "%$search%";
            $params[] = "%$search%";
            $params[] = "%$search%";
        }

        $stmt = $db->prepare($sql);
        $stmt->execute($params);
        Response::success($stmt->fetchAll());
    }

    private function getAssignedWarehouseIds(int $tenantId, int $userId): array
    {
        $db = $this->inventoryModel->getDb();
        $user = $_REQUEST['user'];
        $role = $user['role'] ?? 'Staff';

        // Admins see all warehouses
        if (in_array($role, ['Admin', 'Super Admin'])) {
            $stmt = $db->prepare("SELECT id FROM warehouses WHERE tenant_id = ? AND status = 'active'");
            $stmt->execute([$tenantId]);
            return $stmt->fetchAll(PDO::FETCH_COLUMN);
        }

        $stmt = $db->prepare("SELECT warehouse_id FROM user_warehouses WHERE tenant_id = ? AND user_id = ?");
        $stmt->execute([$tenantId, $userId]);
        return $stmt->fetchAll(PDO::FETCH_COLUMN);
    }

    public function storeWarehouse(): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $data = $this->getJsonBody();
        $this->validate($data, ['name' => 'required']);

        $db = $this->inventoryModel->getDb();
        $isDefault = !empty($data['is_default']) ? 1 : 0;

        if ($isDefault) {
            $stmt = $db->prepare("UPDATE warehouses SET is_default = 0 WHERE tenant_id = :tid");
            $stmt->execute([':tid' => $tenantId]);
        }

        $sql = "INSERT INTO warehouses 
                (tenant_id, name, address, city, state, pincode, is_default, status) 
                VALUES (:tid, :name, :addr, :city, :state, :pin, :def, 'active')";
        
        $stmt = $db->prepare($sql);
        $stmt->execute([
            ':tid' => $tenantId,
            ':name' => $data['name'],
            ':addr' => $data['address'] ?? null,
            ':city' => $data['city'] ?? null,
            ':state' => $data['state'] ?? null,
            ':pin' => $data['pincode'] ?? null,
            ':def' => $isDefault
        ]);

        Response::success(['id' => $db->lastInsertId()], 'Warehouse created successfully');
    }

    public function updateWarehouse(string $id): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $data = $this->getJsonBody();
        $this->validate($data, ['name' => 'required']);

        $db = $this->inventoryModel->getDb();
        $isDefault = !empty($data['is_default']) ? 1 : 0;

        if ($isDefault) {
            $stmt = $db->prepare("UPDATE warehouses SET is_default = 0 WHERE tenant_id = :tid");
            $stmt->execute([':tid' => $tenantId]);
        }

        $sql = "UPDATE warehouses 
                SET name = :name, address = :addr, city = :city, state = :state, 
                    pincode = :pin, is_default = :def 
                WHERE id = :id AND tenant_id = :tid";
        
        $stmt = $db->prepare($sql);
        $stmt->execute([
            ':name' => $data['name'],
            ':addr' => $data['address'] ?? null,
            ':city' => $data['city'] ?? null,
            ':state' => $data['state'] ?? null,
            ':pin' => $data['pincode'] ?? null,
            ':def' => $isDefault,
            ':id' => (int) $id,
            ':tid' => $tenantId
        ]);

        Response::success([], 'Warehouse updated successfully');
    }

    public function deleteWarehouse(string $id): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $db = $this->inventoryModel->getDb();
        
        // Don't delete if it's the default warehouse
        $stmt = $db->prepare("SELECT is_default FROM warehouses WHERE id = ? AND tenant_id = ?");
        $stmt->execute([(int) $id, $tenantId]);
        if ($stmt->fetchColumn()) {
            Response::error('Cannot delete default warehouse');
        }

        $stmt = $db->prepare("UPDATE warehouses SET status = 'inactive' WHERE id = ? AND tenant_id = ?");
        $stmt->execute([(int) $id, $tenantId]);

        Response::success([], 'Warehouse deactivated');
    }

    public function assignUserWarehouses(string $id): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $data = $this->getJsonBody();
        if (!isset($data['warehouse_ids']) || !is_array($data['warehouse_ids'])) {
            Response::error('Invalid warehouse list');
        }

        $db = $this->inventoryModel->getDb();
        $db->beginTransaction();
        try {
            $stmt = $db->prepare("DELETE FROM user_warehouses WHERE user_id = ? AND tenant_id = ?");
            $stmt->execute([(int) $id, $tenantId]);

            $stmt = $db->prepare("INSERT INTO user_warehouses (user_id, warehouse_id, tenant_id) VALUES (?, ?, ?)");
            foreach ($data['warehouse_ids'] as $whId) {
                $stmt->execute([(int) $id, (int) $whId, $tenantId]);
            }

            $db->commit();
            Response::success([], 'Assignments updated');
        } catch (\Exception $e) {
            $db->rollBack();
            Response::error($e->getMessage());
        }
    }

    public function getUserWarehouses(string $id): void
    {
        $tenantId = (int) $_REQUEST['tenant_id'];
        $db = $this->inventoryModel->getDb();
        $stmt = $db->prepare("SELECT warehouse_id FROM user_warehouses WHERE user_id = ? AND tenant_id = ?");
        $stmt->execute([(int) $id, $tenantId]);
        Response::success($stmt->fetchAll(PDO::FETCH_COLUMN));
    }
}
