<?php
declare(strict_types=1);

require_once '../config/database.php';
require_once '../app/helpers/rbac.php';
require_once '../app/helpers/audit.php';
require_once '../app/helpers/api_security.php';
require_once '../app/helpers/soft_delete.php';

header('Content-Type: application/json');

requireApiLogin();
enforceCsrfForUnsafeRequest();

$action = $_GET['action'] ?? '';

if (!isAdmin() && !can('parts.view')) {
    respond(['status' => 'error', 'message' => 'Unauthorized']);
}

try {
    switch ($action) {
        case 'list': handleList($pdo); break;
        case 'save': handleSave($pdo); break;
        case 'delete': handleDelete($pdo); break;
        case 'categories': handleCategories($pdo); break;
        case 'suppliers': handleSuppliers($pdo); break;
        case 'catalog': handleCatalog($pdo); break;
        case 'bin_locations': handleBinLocations($pdo); break;
        case 'transactions': handleTransactions($pdo); break;
        case 'save_transaction': handleSaveTransaction($pdo); break;
        case 'low_stock': handleLowStock($pdo); break;
        default: respond(['status' => 'error', 'message' => 'Unknown action']);
    }
} catch (Exception $e) {
    respond(['status' => 'error', 'message' => $e->getMessage()]);
}

function respond(array $payload): void { apiRespond($payload); }

function doAudit(PDO $pdo, string $action, string $description, ?int $recordId = null): void {
    audit($pdo, (int)($_SESSION['user_id'] ?? 0), $action, 'part', $recordId ?? 0, $description, null, null);
}

function handleList(PDO $pdo): void
{
    $where = ['p.deleted_at IS NULL'];
    $params = [];
    $searchable = ['p.name', 'p.part_number', 'COALESCE(s.name, p.supplier_name)', 'pc.name'];

    if (!empty($_GET['category_id'])) {
        $where[] = 'p.category_id = :category_id';
        $params['category_id'] = (int)$_GET['category_id'];
    }
    if (!empty($_GET['low_stock'])) {
        $where[] = 'p.reorder_level IS NOT NULL AND p.quantity_in_stock <= p.reorder_level';
    }
    if (!empty($_GET['search'])) {
        $q = '%' . $_GET['search'] . '%';
        $conds = [];
        foreach ($searchable as $col) {
            $conds[] = "{$col} LIKE :q";
        }
        $where[] = '(' . implode(' OR ', $conds) . ')';
        $params['q'] = $q;
    }

    $whereSql = implode(' AND ', $where);
    $stmt = $pdo->prepare("
        SELECT p.*, pc.name AS category_name,
               COALESCE(s.name, p.supplier_name) AS supplier_name,
               cc.name AS catalog_name, cc.part_number AS catalog_part_number,
               bl.name AS bin_location_name
        FROM parts p
        LEFT JOIN part_categories pc ON pc.id = p.category_id
        LEFT JOIN suppliers s ON s.id = p.supplier_id AND s.deleted_at IS NULL
        LEFT JOIN part_catalog cc ON cc.id = p.catalog_id
        LEFT JOIN bin_locations bl ON bl.id = p.bin_location_id AND bl.deleted_at IS NULL
        WHERE {$whereSql}
        ORDER BY p.name ASC
    ");
    $stmt->execute($params);
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleSave(PDO $pdo): void
{
    if (!isAdmin() && !can('parts.create') && !can('parts.edit')) {
        respond(['status' => 'error', 'message' => 'Unauthorized']);
    }

    $id = (int)($_POST['id'] ?? 0);
    $supplierId = !empty($_POST['supplier_id']) ? (int)$_POST['supplier_id'] : null;
    $catalogId = !empty($_POST['catalog_id']) ? (int)$_POST['catalog_id'] : null;

    $name = trim($_POST['name'] ?? '');
    $partNumber = trim($_POST['part_number'] ?? '');
    $supplierName = trim($_POST['supplier_name'] ?? '');

    // Auto-fill from catalog
    if ($catalogId && (!$name || !$partNumber)) {
        $stmt = $pdo->prepare("SELECT name, part_number, default_unit_cost, default_reorder_level, unit_of_measure, category_id FROM part_catalog WHERE id = :id");
        $stmt->execute(['id' => $catalogId]);
        $catalog = $stmt->fetch();
        if ($catalog) {
            if (!$name) $name = $catalog['name'];
            if (!$partNumber) $partNumber = $catalog['part_number'];
            if (empty($_POST['unit_cost']) && $catalog['default_unit_cost']) $_POST['unit_cost'] = (string)$catalog['default_unit_cost'];
            if (empty($_POST['reorder_level']) && $catalog['default_reorder_level']) $_POST['reorder_level'] = (string)$catalog['default_reorder_level'];
            if (empty($_POST['unit_of_measure']) && $catalog['unit_of_measure']) $_POST['unit_of_measure'] = $catalog['unit_of_measure'];
            if (empty($_POST['category_id']) && $catalog['category_id']) $_POST['category_id'] = (string)$catalog['category_id'];
        }
    }

    // Auto-fill supplier_name from suppliers table
    if ($supplierId && !$supplierName) {
        $stmt = $pdo->prepare("SELECT name FROM suppliers WHERE id = :id AND deleted_at IS NULL");
        $stmt->execute(['id' => $supplierId]);
        $s = $stmt->fetch();
        if ($s) $supplierName = $s['name'];
    }

    // Auto-fill bin_location from bin_locations table
    $binLocationId = !empty($_POST['bin_location_id']) ? (int)$_POST['bin_location_id'] : null;
    $binLocation = trim($_POST['bin_location'] ?? '');
    if ($binLocationId && !$binLocation) {
        $stmt = $pdo->prepare("SELECT name FROM bin_locations WHERE id = :id AND deleted_at IS NULL");
        $stmt->execute(['id' => $binLocationId]);
        $b = $stmt->fetch();
        if ($b) $binLocation = $b['name'];
    }

    $data = [
        'name' => $name,
        'part_number' => $partNumber,
        'category_id' => !empty($_POST['category_id']) ? (int)$_POST['category_id'] : null,
        'supplier_id' => $supplierId,
        'catalog_id' => $catalogId,
        'bin_location_id' => $binLocationId,
        'quantity_in_stock' => (float)($_POST['quantity_in_stock'] ?? 0),
        'reorder_level' => !empty($_POST['reorder_level']) ? (float)$_POST['reorder_level'] : null,
        'unit_cost' => !empty($_POST['unit_cost']) ? (float)$_POST['unit_cost'] : null,
        'supplier_name' => $supplierName,
        'bin_location' => $binLocation,
        'unit_of_measure' => trim($_POST['unit_of_measure'] ?? ''),
        'description' => trim($_POST['description'] ?? ''),
    ];

    if (!$data['name']) {
        respond(['status' => 'error', 'message' => 'Part name is required']);
    }

    if ($id > 0) {
        $data['updated_at'] = date('Y-m-d H:i:s');
        $data['id'] = $id;
        $sets = [];
        foreach ($data as $col => $val) {
            $sets[] = "{$col} = :{$col}";
        }
        $pdo->prepare("UPDATE parts SET " . implode(', ', $sets) . " WHERE id = :id")->execute($data);
        doAudit($pdo, 'update', "Part #{$id} updated", $id);
        respond(['status' => 'success', 'message' => 'Part updated']);
    } else {
        $cols = implode(', ', array_keys($data));
        $vals = ':' . implode(', :', array_keys($data));
        $pdo->prepare("INSERT INTO parts ({$cols}) VALUES ({$vals})")->execute($data);
        $newId = (int)$pdo->lastInsertId();
        doAudit($pdo, 'create', "Part #{$newId} created", $newId);
        respond(['status' => 'success', 'message' => 'Part created', 'id' => $newId]);
    }
}

function handleDelete(PDO $pdo): void
{
    if (!isAdmin() && !can('parts.delete')) {
        respond(['status' => 'error', 'message' => 'Unauthorized']);
    }
    $id = (int)($_POST['id'] ?? 0);
    if ($id <= 0) respond(['status' => 'error', 'message' => 'Invalid ID']);
    softDelete($pdo, 'parts', $id);
    doAudit($pdo, 'delete', "Part #{$id} deleted", $id);
    respond(['status' => 'success', 'message' => 'Part deleted']);
}

function handleCategories(PDO $pdo): void
{
    $stmt = $pdo->query("SELECT * FROM part_categories ORDER BY name ASC");
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleSuppliers(PDO $pdo): void
{
    $stmt = $pdo->query("SELECT id, name, contact_person, phone, email FROM suppliers WHERE deleted_at IS NULL AND status = 'active' ORDER BY name ASC");
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleCatalog(PDO $pdo): void
{
    $where = ['c.is_active = 1'];
    $params = [];
    if (!empty($_GET['category_id'])) {
        $where[] = 'c.category_id = :category_id';
        $params['category_id'] = (int)$_GET['category_id'];
    }
    $stmt = $pdo->prepare("SELECT c.*, pc.name AS category_name FROM part_catalog c LEFT JOIN part_categories pc ON pc.id = c.category_id WHERE " . implode(' AND ', $where) . " ORDER BY c.name ASC");
    $stmt->execute($params);
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleBinLocations(PDO $pdo): void
{
    $stmt = $pdo->query("SELECT id, name, description FROM bin_locations WHERE deleted_at IS NULL AND is_active = 1 ORDER BY name ASC");
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleTransactions(PDO $pdo): void
{
    $where = ['1=1'];
    $params = [];

    if (!empty($_GET['part_id'])) {
        $where[] = 'pt.part_id = :part_id';
        $params['part_id'] = (int)$_GET['part_id'];
    }

    $whereSql = implode(' AND ', $where);
    $stmt = $pdo->prepare("
        SELECT pt.*, p.name AS part_name, p.part_number
        FROM part_transactions pt
        LEFT JOIN parts p ON p.id = pt.part_id
        WHERE {$whereSql}
        ORDER BY pt.created_at DESC
    ");
    $stmt->execute($params);
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleSaveTransaction(PDO $pdo): void
{
    if (!isAdmin() && !can('parts.edit')) {
        respond(['status' => 'error', 'message' => 'Unauthorized']);
    }

    $partId = (int)($_POST['part_id'] ?? 0);
    $type = $_POST['transaction_type'] ?? '';
    $quantity = (int)($_POST['quantity'] ?? 0);
    $unitCost = !empty($_POST['unit_cost']) ? (float)$_POST['unit_cost'] : null;
    $notes = trim($_POST['notes'] ?? '');

    if (!$partId || !$type || $quantity <= 0) {
        respond(['status' => 'error', 'message' => 'Part, transaction type, and quantity are required']);
    }

    $pdo->beginTransaction();
    try {
        $stmt = $pdo->prepare("INSERT INTO part_transactions (part_id, transaction_type, quantity, unit_cost, notes, created_by) VALUES (:part_id, :type, :quantity, :unit_cost, :notes, :created_by)");
        $stmt->execute([
            'part_id' => $partId, 'type' => $type, 'quantity' => $quantity,
            'unit_cost' => $unitCost, 'notes' => $notes,
            'created_by' => (int)($_SESSION['user_id'] ?? 0),
        ]);

        if ($type === 'purchase' || $type === 'return') {
            $pdo->prepare("UPDATE parts SET quantity_in_stock = quantity_in_stock + :qty WHERE id = :id")->execute(['qty' => $quantity, 'id' => $partId]);
        } elseif ($type === 'usage' || $type === 'adjustment') {
            $pdo->prepare("UPDATE parts SET quantity_in_stock = quantity_in_stock - :qty WHERE id = :id")->execute(['qty' => $quantity, 'id' => $partId]);
        }

        $pdo->commit();
        doAudit($pdo, 'transaction', "{$type} of {$quantity} for part #{$partId}", $partId);
        respond(['status' => 'success', 'message' => 'Transaction recorded']);
    } catch (Exception $e) {
        $pdo->rollBack();
        respond(['status' => 'error', 'message' => $e->getMessage()]);
    }
}

function handleLowStock(PDO $pdo): void
{
    $stmt = $pdo->query("
        SELECT p.*, pc.name AS category_name,
               (p.quantity_in_stock - p.reorder_level) AS deficit
        FROM parts p
        LEFT JOIN part_categories pc ON pc.id = p.category_id
        WHERE p.reorder_level IS NOT NULL AND p.quantity_in_stock <= p.reorder_level AND p.deleted_at IS NULL
        ORDER BY (p.quantity_in_stock / p.reorder_level) ASC
    ");
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}
