<?php

$tokenRec = require_valid_token_web();

$callerRole     = $tokenRec['role'];
$callerEntityID = $tokenRec['entityID'] ?? '';

switch ($method) {

case 'GET':
    try {
        [$pdo, $tmpDb, $lockFp] = qdb_open_read_or_fail();

        $clientCode = trim((string)($_GET['clientCode'] ?? ''));
        if ($clientCode !== '' && !empty($_GET['detail'])) {
            require_once __DIR__ . '/../lib/submissions.php';
            $detail = qdb_client_detail($pdo, $tokenRec, $clientCode);
            qdb_discard($tmpDb, $lockFp);
            json_success($detail);
        }

        $archiveFilter = trim((string)($_GET['archiveFilter'] ?? 'active'));
        if (!in_array($archiveFilter, ['active', 'archived', 'all'], true)) {
            $archiveFilter = 'active';
        }
        [$clause, $params] = rbac_client_filter($tokenRec, 'cl', $archiveFilter);
        $stmt = $pdo->prepare(
            "SELECT cl.clientCode, cl.coachID, cl.archived, cl.archivedAt,
                    co.username AS coachUsername,
                    CASE WHEN EXISTS (
                        SELECT 1 FROM completed_questionnaire cq WHERE cq.clientCode = cl.clientCode
                    ) OR EXISTS (
                        SELECT 1 FROM questionnaire_submission qs WHERE qs.clientCode = cl.clientCode
                    ) THEN 1 ELSE 0 END AS hasResponseData
             FROM client cl
             LEFT JOIN coach co ON co.coachID = cl.coachID
             WHERE $clause
             ORDER BY cl.archived ASC, hasResponseData DESC, cl.clientCode ASC"
        );
        foreach ($params as $k => $v) $stmt->bindValue($k, $v);
        $stmt->execute();
        $clients = $stmt->fetchAll(PDO::FETCH_ASSOC);

        require_once __DIR__ . '/../lib/submissions.php';
        $scoringSummary = qdb_clients_scoring_summary_for_list($pdo, $tokenRec);
        foreach ($clients as &$client) {
            $client['scoringProfiles'] = qdb_client_scoring_dots_for_client(
                $client['clientCode'],
                $scoringSummary
            );
        }
        unset($client);

        qdb_discard($tmpDb, $lockFp);
        json_success([
            'clients'          => $clients,
            'scoringProfiles'  => $scoringSummary['profiles'],
        ]);
    } catch (Throwable $e) {
        qdb_handler_fail($e, 'clients', null, $tmpDb ?? null, $lockFp ?? null);
    }
    break;

case 'POST':
    $body       = read_json_body();
    $clientCode = trim($body['clientCode'] ?? '');
    $coachID    = trim($body['coachID'] ?? '');

    if ($clientCode === '' || $coachID === '') {
        json_error('MISSING_FIELDS', 'clientCode and coachID are required', 400);
    }

    try {
        [$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();

        // Validate coach exists and caller is allowed to assign to them
        if ($callerRole === 'supervisor') {
            $chkCoach = $pdo->prepare("SELECT coachID FROM coach WHERE coachID = :cid AND supervisorID = :sid");
            $chkCoach->execute([':cid' => $coachID, ':sid' => $callerEntityID]);
        } else {
            $chkCoach = $pdo->prepare("SELECT coachID FROM coach WHERE coachID = :cid");
            $chkCoach->execute([':cid' => $coachID]);
        }
        if (!$chkCoach->fetch()) {
            qdb_discard($tmpDb, $lockFp);
            json_error('NOT_FOUND', 'Counselor not found or not authorized', 404);
        }

        $chk = $pdo->prepare("SELECT clientCode FROM client WHERE clientCode = :cc");
        $chk->execute([':cc' => $clientCode]);
        if ($chk->fetch()) {
            qdb_discard($tmpDb, $lockFp);
            json_error('DUPLICATE', 'Client code already exists', 409);
        }

        $pdo->prepare(
            "INSERT INTO client (clientCode, coachID, archived, archivedAt) VALUES (:cc, :cid, 0, 0)"
        )->execute([':cc' => $clientCode, ':cid' => $coachID]);

        qdb_save($tmpDb, $lockFp);
        json_success(['clientCode' => $clientCode, 'coachID' => $coachID]);
    } catch (Throwable $e) {
        qdb_handler_fail($e, 'clients', null, $tmpDb ?? null, $lockFp ?? null);
    }
    break;

case 'PUT':
    $body       = read_json_body();
    $clientCode = trim((string)($body['clientCode'] ?? ''));
    $profileID  = trim((string)($body['profileID'] ?? ''));
    $coachBand  = trim((string)($body['coachBand'] ?? ''));

    if ($clientCode === '' || $profileID === '' || $coachBand === '') {
        json_error('MISSING_FIELDS', 'clientCode, profileID, and coachBand are required', 400);
    }

    $calculatedBand = trim((string)($body['calculatedBand'] ?? ''));
    $weightedTotal  = isset($body['weightedTotal']) ? (float)$body['weightedTotal'] : null;

    try {
        [$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();

        [$clause, $params] = rbac_client_filter($tokenRec, 'cl');
        $chk = $pdo->prepare(
            "SELECT clientCode FROM client cl WHERE cl.clientCode = :cc AND ($clause)"
        );
        $chk->execute(array_merge([':cc' => $clientCode], $params));
        if (!$chk->fetch()) {
            qdb_discard($tmpDb, $lockFp);
            json_error('NOT_FOUND', 'Client not found or not authorized', 404);
        }

        require_once __DIR__ . '/../lib/scoring.php';
        if (!qdb_is_valid_scoring_band($coachBand)) {
            qdb_discard($tmpDb, $lockFp);
            json_error('INVALID_FIELD', 'coachBand must be green, yellow, or red', 400);
        }

        $profile = qdb_save_coach_scoring_review(
            $pdo,
            $clientCode,
            $profileID,
            $coachBand,
            (string)($tokenRec['userID'] ?? ''),
            $weightedTotal,
            $calculatedBand !== '' ? $calculatedBand : null,
        );

        qdb_save($tmpDb, $lockFp);
        json_success(['profile' => $profile]);
    } catch (InvalidArgumentException $e) {
        qdb_discard($tmpDb ?? null, $lockFp ?? null);
        json_error('INVALID_FIELD', $e->getMessage(), 400);
    } catch (RuntimeException $e) {
        qdb_discard($tmpDb ?? null, $lockFp ?? null);
        json_error('NOT_FOUND', $e->getMessage(), 404);
    } catch (Throwable $e) {
        qdb_handler_fail($e, 'clients', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
    }
    break;

case 'PATCH':
    $body       = read_json_body();
    $clientCode = trim((string)($body['clientCode'] ?? ''));
    if ($clientCode === '' || !array_key_exists('archived', $body)) {
        json_error('MISSING_FIELDS', 'clientCode and archived are required', 400);
    }
    $archived = !empty($body['archived']) ? 1 : 0;

    try {
        [$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();

        [$clause, $params] = rbac_client_filter($tokenRec, 'cl', 'all');
        $chk = $pdo->prepare(
            "SELECT clientCode, archived FROM client cl WHERE cl.clientCode = :cc AND ($clause)"
        );
        $chk->execute(array_merge([':cc' => $clientCode], $params));
        $row = $chk->fetch(PDO::FETCH_ASSOC);
        if (!$row) {
            qdb_discard($tmpDb, $lockFp);
            json_error('NOT_FOUND', 'Client not found or not authorized', 404);
        }

        $archivedAt = $archived ? time() : 0;
        $pdo->prepare(
            'UPDATE client SET archived = :a, archivedAt = :at WHERE clientCode = :cc'
        )->execute([':a' => $archived, ':at' => $archivedAt, ':cc' => $clientCode]);

        qdb_save($tmpDb, $lockFp);
        json_success([
            'clientCode' => $clientCode,
            'archived'   => $archived,
            'archivedAt' => $archivedAt,
        ]);
    } catch (Throwable $e) {
        qdb_handler_fail($e, 'clients', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
    }
    break;

case 'DELETE':
    $body       = read_json_body();
    $clientCode = trim($body['clientCode'] ?? '');

    if ($clientCode === '') {
        json_error('MISSING_FIELDS', 'clientCode is required', 400);
    }

    try {
        [$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();

        // Verify the client exists and the caller can see it (RBAC)
        [$clause, $params] = rbac_client_filter($tokenRec, 'cl');
        $chk = $pdo->prepare(
            "SELECT clientCode FROM client cl WHERE cl.clientCode = :cc AND ($clause)"
        );
        $chk->execute(array_merge([':cc' => $clientCode], $params));
        if (!$chk->fetch()) {
            qdb_discard($tmpDb, $lockFp);
            json_error('NOT_FOUND', 'Client not found or not authorized', 404);
        }

        require_once __DIR__ . '/../lib/submissions.php';

        $pdo->beginTransaction();
        qdb_delete_client_response_data($pdo, [$clientCode]);
        $pdo->prepare('DELETE FROM client WHERE clientCode = :cc')
            ->execute([':cc' => $clientCode]);
        $pdo->commit();

        qdb_save($tmpDb, $lockFp);
        json_success([]);
    } catch (Throwable $e) {
        qdb_handler_fail($e, 'clients', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
    }
    break;

default:
    json_error('METHOD_NOT_ALLOWED', 'Method not allowed', 405);
}
