<?php

// ============================================================
// MANAGER: UPDATE TEAM KPI ACTUALS API
// File: api/manager_update_team_kpi.php
//
// Method: POST
//
// ------------------------------------------------------------
// ACTION 1: LIST  (fetch team KPI actuals for a period, so the
//           manager can pick which one to update)
// ------------------------------------------------------------
// {
//     "action": "list",
//     "user_id": "EMP031",        // manager's id (string)
//     "period": "2026-07"         // OPTIONAL. Defaults to current month (YYYY-MM)
// }
//
// ------------------------------------------------------------
// ACTION 2: UPDATE  (manager sets/corrects an actual value for
//           one of their team member's KPI rows)
// ------------------------------------------------------------
// {
//     "action": "update",
//     "user_id": "EMP031",        // manager's id (string)
//     "kpi_id": "45",             // id of the kpi_actuals row (from "list")
//     "actual_value": 87.5,
//     "remarks": "Verified against CRM export for July."
// }
//
// ------------------------------------------------------------
// FIX (2026-07):
// The Flutter app was sending the manager's id under the key
// "manager_id" instead of "user_id", which produced
// "Valid user_id is required." even though a valid id was sent.
// This endpoint now accepts EITHER "user_id" OR "manager_id"
// (user_id takes priority if both are present), so it works
// regardless of which key the client uses.
// ------------------------------------------------------------
//
// FIX (2026-07): kpi_id is now bound with a type-safe helper —
// previously it was force-bound as an integer ("i") even though
// it travels through the request as a string, which can throw a
// TypeError under strict mysqli reporting. It is now validated
// with is_numeric()/ctype_digit() on the trimmed string BEFORE
// being cast to an actual PHP int, and bound as "i" using that
// real int — never a raw string.
// ------------------------------------------------------------
//
// SECURITY:
// - Only role='manager' users may call this.
// - On UPDATE, the target kpi row's employee must report to this
//   manager (matched the same way dashboard_manager.php does it:
//   via the TEXT column `reporting_manager` = manager's username),
//   otherwise 403.
// ------------------------------------------------------------
//
// Table `kpi_actuals` is auto-created if missing (with sensible
// columns) so this API works even before a migration is run.
// Adjust ensureColumn()/CREATE TABLE below if your real schema
// already has different column names.
// ============================================================

header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

date_default_timezone_set('Asia/Kolkata');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit();
}

require_once '../config.php';

function sendResponse(int $statusCode, bool $success, string $message, array $extra = []): void {
    http_response_code($statusCode);
    echo json_encode(
        array_merge(["success" => $success, "message" => $message], $extra),
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );
    exit();
}

function isValidStringId(string $id): bool {
    return $id !== ''
        && strlen($id) <= 30
        && preg_match('/^[A-Za-z0-9_\-]+$/', $id) === 1;
}

function tableExists($conn, $table) {
    $t = $conn->real_escape_string($table);
    $res = $conn->query("SHOW TABLES LIKE '{$t}'");
    return $res && $res->num_rows > 0;
}

function columnExists($conn, $table, $column) {
    $t = $conn->real_escape_string($table);
    $c = $conn->real_escape_string($column);
    $res = $conn->query("SHOW COLUMNS FROM `{$t}` LIKE '{$c}'");
    return $res && $res->num_rows > 0;
}

function ensureColumn($conn, $table, $column, $definition) {
    if (!columnExists($conn, $table, $column)) {
        $conn->query("ALTER TABLE `{$table}` ADD COLUMN `{$column}` {$definition}");
    }
}

// ============================================================
// ENSURE kpi_actuals TABLE EXISTS
// ============================================================

if (!tableExists($conn, 'kpi_actuals')) {
    $conn->query("CREATE TABLE IF NOT EXISTS kpi_actuals (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id VARCHAR(30) NOT NULL,
        kpi_period VARCHAR(20) NOT NULL,
        kpi_name VARCHAR(150) NOT NULL,
        target_value DECIMAL(12,2) NULL DEFAULT NULL,
        actual_value DECIMAL(12,2) NULL DEFAULT NULL,
        remarks TEXT NULL DEFAULT NULL,
        status VARCHAR(20) NOT NULL DEFAULT 'Pending',
        updated_by VARCHAR(30) NULL DEFAULT NULL,
        updated_by_role VARCHAR(20) NULL DEFAULT NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX idx_user_period (user_id, kpi_period)
    ) ENGINE=InnoDB");
}

// In case the table already existed with an older/partial shape.
ensureColumn($conn, 'kpi_actuals', 'target_value', "DECIMAL(12,2) NULL DEFAULT NULL");
ensureColumn($conn, 'kpi_actuals', 'actual_value', "DECIMAL(12,2) NULL DEFAULT NULL");
ensureColumn($conn, 'kpi_actuals', 'remarks', "TEXT NULL DEFAULT NULL");
ensureColumn($conn, 'kpi_actuals', 'status', "VARCHAR(20) NOT NULL DEFAULT 'Pending'");
ensureColumn($conn, 'kpi_actuals', 'updated_by', "VARCHAR(30) NULL DEFAULT NULL");
ensureColumn($conn, 'kpi_actuals', 'updated_by_role', "VARCHAR(20) NULL DEFAULT NULL");

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    sendResponse(405, false, "Only POST method is allowed.");
}

$rawData = file_get_contents("php://input");
$data = json_decode($rawData, true);
if (!is_array($data)) {
    $data = $_POST;
}

$action = trim((string)($data['action'] ?? ''));

// ============================================================
// MANAGER ID
//
// FIX: accept EITHER "user_id" OR "manager_id" from the client,
// since the Flutter app sends "manager_id" on this screen while
// other screens send "user_id". user_id wins if both are sent.
// ============================================================

$managerId = trim((string)($data['user_id'] ?? $data['manager_id'] ?? ''));

if (!isValidStringId($managerId)) {
    $conn->close();
    sendResponse(400, false, "Valid manager id is required.");
}

// ============================================================
// VALIDATE MANAGER
// ============================================================

$stmt = $conn->prepare("SELECT id, username, role FROM users WHERE id = ? LIMIT 1");
if (!$stmt) {
    $conn->close();
    sendResponse(500, false, "Unable to validate manager.");
}
$stmt->bind_param("s", $managerId);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
    $stmt->close();
    $conn->close();
    sendResponse(404, false, "Manager not found.");
}
$manager = $result->fetch_assoc();
$stmt->close();

$role = strtolower(trim($manager['role'] ?? ''));
if ($role !== 'manager') {
    $conn->close();
    sendResponse(403, false, "Only managers can update team KPI actuals.");
}

$managerUsername = trim((string)($manager['username'] ?? ''));

// ============================================================
// ACTION: LIST
// ============================================================

if ($action === 'list') {

    $period = trim((string)($data['period'] ?? ''));
    if ($period === '' || !preg_match('/^\d{4}-\d{2}$/', $period)) {
        $period = date('Y-m'); // default: current month
    }

    // Team members matched the SAME way dashboard_manager.php does:
    // via the TEXT column `reporting_manager` = manager's username.
    $stmt = $conn->prepare("
        SELECT
            k.id,
            k.user_id,
            u.username        AS employee_name,
            k.kpi_period,
            k.kpi_name,
            k.target_value,
            k.actual_value,
            k.remarks,
            k.status,
            k.updated_by,
            k.updated_by_role,
            k.updated_at
        FROM kpi_actuals k
        JOIN users u ON u.id = k.user_id
        WHERE LOWER(TRIM(u.reporting_manager)) = LOWER(TRIM(?))
          AND k.kpi_period = ?
        ORDER BY u.username ASC, k.kpi_name ASC
    ");

    if (!$stmt) {
        $conn->close();
        sendResponse(500, false, "Unable to load team KPI actuals.");
    }

    $stmt->bind_param("ss", $managerUsername, $period);
    $stmt->execute();
    $res = $stmt->get_result();

    $rows = [];
    while ($r = $res->fetch_assoc()) {
        $rows[] = [
            "kpi_id"        => (string)$r['id'],
            "user_id"       => (string)$r['user_id'],
            "employee_name" => $r['employee_name'],
            "period"        => $r['kpi_period'],
            "kpi_name"      => $r['kpi_name'],
            "target_value"  => $r['target_value'] !== null ? (float)$r['target_value'] : null,
            "actual_value"  => $r['actual_value'] !== null ? (float)$r['actual_value'] : null,
            "remarks"       => $r['remarks'],
            "status"        => $r['status'],
            "updated_by"        => $r['updated_by'],
            "updated_by_role"   => $r['updated_by_role'],
            "updated_at"        => $r['updated_at'],
        ];
    }
    $stmt->close();
    $conn->close();

    sendResponse(200, true, "Team KPI actuals loaded successfully.", [
        "period" => $period,
        "manager" => [
            "user_id" => (string)$manager['id'],
            "username" => $manager['username'],
        ],
        "kpi_actuals" => $rows,
    ]);
}

// ============================================================
// ACTION: UPDATE
// ============================================================

if ($action === 'update') {

    // --------------------------------------------------------
    // kpi_id — accept it as a string OR a number from JSON,
    // validate it, then cast to a REAL PHP int before binding
    // with type "i". This avoids type errors that can occur
    // when a string value is force-bound as an integer.
    // --------------------------------------------------------

    $kpiIdRaw = $data['kpi_id'] ?? '';
    $kpiIdStr = trim((string)$kpiIdRaw);

    if ($kpiIdStr === '' || !ctype_digit($kpiIdStr)) {
        $conn->close();
        sendResponse(400, false, "Valid kpi_id is required.");
    }

    $kpiId = (int)$kpiIdStr;

    if (!array_key_exists('actual_value', $data) || $data['actual_value'] === '' || $data['actual_value'] === null) {
        $conn->close();
        sendResponse(400, false, "actual_value is required.");
    }

    if (!is_numeric($data['actual_value'])) {
        $conn->close();
        sendResponse(400, false, "actual_value must be a number.");
    }

    $actualValue = (float)$data['actual_value'];
    $remarks = trim((string)($data['remarks'] ?? ''));

    // ------------------------------------------------------
    // Confirm this KPI row belongs to a member of THIS manager's
    // team, before allowing the update.
    // ------------------------------------------------------

    $ownStmt = $conn->prepare("
        SELECT k.id
        FROM kpi_actuals k
        JOIN users u ON u.id = k.user_id
        WHERE k.id = ?
          AND LOWER(TRIM(u.reporting_manager)) = LOWER(TRIM(?))
        LIMIT 1
    ");

    if (!$ownStmt) {
        $conn->close();
        sendResponse(500, false, "Unable to verify KPI ownership.");
    }

    $ownStmt->bind_param("is", $kpiId, $managerUsername);
    $ownStmt->execute();
    $ownResult = $ownStmt->get_result();

    if ($ownResult->num_rows === 0) {
        $ownStmt->close();
        $conn->close();
        sendResponse(403, false, "This KPI record does not belong to your team.");
    }
    $ownStmt->close();

    // ------------------------------------------------------
    // UPDATE
    // ------------------------------------------------------

    $updateStmt = $conn->prepare("
        UPDATE kpi_actuals
        SET actual_value = ?,
            remarks = ?,
            status = 'Reviewed',
            updated_by = ?,
            updated_by_role = 'manager',
            updated_at = NOW()
        WHERE id = ?
    ");

    if (!$updateStmt) {
        $conn->close();
        sendResponse(500, false, "Unable to update KPI actual.");
    }

    $updateStmt->bind_param("dssi", $actualValue, $remarks, $managerId, $kpiId);
    $updateStmt->execute();
    $updateStmt->close();

    $conn->close();

    sendResponse(200, true, "KPI actual updated successfully.", [
        "kpi_id" => (string)$kpiId,
        "actual_value" => $actualValue,
        "remarks" => $remarks,
        "status" => "Reviewed",
        "updated_by" => $managerId,
    ]);
}

// ============================================================
// UNKNOWN ACTION
// ============================================================

$conn->close();
sendResponse(400, false, "Invalid or missing action. Use 'list' or 'update'.");

?>