<?php
declare(strict_types=1);

/**
 * /functional/friends/action.php
 * POST-обробник дій:
 * - send_friend (user_id)
 * - accept_friend (user_id)
 * - decline_friend (user_id)
 * - cancel_friend (user_id)
 * - remove_friend (user_id)
 * - follow (user_id)
 * - unfollow (user_id)
 *
 * SEO: службовий endpoint => noindex
 *
 * Оновлено:
 * - підключено email-сповіщення 2 етапу для нової заявки в друзі
 * - лист відправляється тільки після реального створення pending-заявки
 * - при already_sent / already_friends / помилці лист не шлеться
 * - помилки модуля email не ламають основну дію дружби
 * - виправлено порядок аргументів у ntf_dispatch_friend_request()
 */

require_once __DIR__ . '/../../includes/start.php';
require_login();

/** @var PDO|null $pdo */
/** @var array|null $me */
$pdo = (isset($pdo) && $pdo instanceof PDO) ? $pdo : db();
$me  = $me ?? current_user();
$meId = (int)($me['id'] ?? 0);

require_once __DIR__ . '/_lib.php';

$notificationsEvents = __DIR__ . '/../notifications/events.php';
if (is_file($notificationsEvents)) {
    require_once $notificationsEvents;
}

/* SEO / no-cache */
if (!headers_sent()) {
    header('X-Robots-Tag: noindex, nofollow, noarchive, nosnippet', true);
    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', true);
    header('Pragma: no-cache', true);
    header('Expires: 0', true);
}

/* helpers */
$isAjax = function_exists('vm_is_ajax') ? vm_is_ajax() : false;

$sendJson = static function (array $data, int $code = 200) use ($isAjax): void {
    if ($isAjax && function_exists('vm_json_exit')) {
        vm_json_exit($data, $code);
    }

    if (!headers_sent()) {
        http_response_code($code);
        header('Content-Type: application/json; charset=UTF-8', true);
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', true);
        header('Pragma: no-cache', true);
    }

    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
};

$redirectBack = static function (string $back, string $res): void {
    $sep = (str_contains($back, '?') ? '&' : '?');
    header('Location: ' . $back . $sep . 'r=' . urlencode($res));
    exit;
};

$sanitizeBack = static function (string $raw): string {
    $raw = trim($raw);

    if (function_exists('safe_local_path')) {
        $raw = (string)safe_local_path($raw, '/functional/friends/');
    } else {
        if ($raw === '') {
            $raw = '/functional/friends/';
        }

        $p = (string)parse_url($raw, PHP_URL_PATH);
        $q = (string)parse_url($raw, PHP_URL_QUERY);

        if ($p === '' || !str_starts_with($p, '/')) {
            $p = '/functional/friends/';
        }

        $raw = $p . ($q !== '' ? ('?' . $q) : '');
    }

    $allowedPrefixes = [
        '/functional/friends/',
        '/profile/',
        '/group/',
        '/',
    ];

    $p2 = (string)parse_url($raw, PHP_URL_PATH);
    if ($p2 === '' || !str_starts_with($p2, '/')) {
        return '/functional/friends/';
    }

    $ok = false;
    foreach ($allowedPrefixes as $pref) {
        if (str_starts_with($p2, $pref)) {
            $ok = true;
            break;
        }
    }

    if (!$ok) {
        return '/functional/friends/';
    }

    return $raw;
};

if (!function_exists('vm_friend_action_find_pending_request_id')) {
    function vm_friend_action_find_pending_request_id(PDO $pdo, int $fromUserId, int $toUserId): int
    {
        if ($fromUserId <= 0 || $toUserId <= 0) {
            return 0;
        }

        try {
            $st = $pdo->prepare("
                SELECT id
                FROM friend_requests
                WHERE from_user_id = ?
                  AND to_user_id = ?
                  AND status = 'pending'
                ORDER BY id DESC
                LIMIT 1
            ");
            $st->execute([$fromUserId, $toUserId]);

            return (int)$st->fetchColumn();
        } catch (Throwable $e) {
            error_log('[friends/action.php find pending request] ' . $e->getMessage());
            return 0;
        }
    }
}

/* базові перевірки */
if ($meId <= 0) {
    if ($isAjax) {
        $sendJson(['ok' => false, 'err' => 'forbidden'], 403);
    }

    http_response_code(403);
    echo "Forbidden";
    exit;
}

if (!vm_friends_ready($pdo)) {
    if ($isAjax) {
        $sendJson(['ok' => false, 'err' => 'db_tables_missing'], 500);
    }

    http_response_code(500);
    echo "DB tables missing: friend_requests/user_follows";
    exit;
}

/* GET/інші методи */
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    if ($isAjax) {
        $sendJson(['ok' => false, 'err' => 'method_not_allowed'], 405);
    }

    header('Location: /functional/friends/');
    exit;
}

/* CSRF */
vm_csrf_check();

/* input */
$do  = trim((string)($_POST['do'] ?? ''));
$uid = (int)($_POST['user_id'] ?? 0);
$backRaw = (string)($_POST['back'] ?? '');
$back = $sanitizeBack($backRaw);

if ($uid <= 0) {
    if ($isAjax) {
        $sendJson(['ok' => false, 'err' => 'bad_user_id'], 400);
    }

    http_response_code(400);
    echo "Bad user_id";
    exit;
}

if ($uid === $meId) {
    $res = 'self';

    if ($isAjax) {
        $sendJson([
            'ok'      => false,
            'res'     => $res,
            'do'      => $do,
            'user_id' => $uid,
        ], 200);
    }

    $redirectBack($back, $res);
}

/* whitelist дій */
$allowed = [
    'send_friend'    => true,
    'accept_friend'  => true,
    'decline_friend' => true,
    'cancel_friend'  => true,
    'remove_friend'  => true,
    'follow'         => true,
    'unfollow'       => true,
];

if (!isset($allowed[$do])) {
    $res = 'unknown';

    if ($isAjax) {
        $sendJson([
            'ok'      => false,
            'res'     => $res,
            'do'      => $do,
            'user_id' => $uid,
        ], 400);
    }

    http_response_code(400);
    echo "Unknown action";
    exit;
}

$res = 'bad';
$friendRequestIdForEmail = 0;
$shouldSendFriendRequestEmail = false;

try {
    switch ($do) {
        case 'send_friend':
            $res = vm_friend_request_send($pdo, $meId, $uid);

            if ($res === 'sent') {
                $friendRequestIdForEmail = vm_friend_action_find_pending_request_id($pdo, $meId, $uid);
                $shouldSendFriendRequestEmail = ($friendRequestIdForEmail > 0);
            }
            break;

        case 'accept_friend':
            $res = vm_friend_request_accept($pdo, $meId, $uid);
            break;

        case 'decline_friend':
            $res = vm_friend_request_decline($pdo, $meId, $uid);
            break;

        case 'cancel_friend':
            $res = vm_friend_request_cancel($pdo, $meId, $uid);
            break;

        case 'remove_friend':
            $res = vm_friend_remove($pdo, $meId, $uid);
            break;

        case 'follow':
            $res = vm_follow_add($pdo, $meId, $uid);
            break;

        case 'unfollow':
            $res = vm_follow_remove($pdo, $meId, $uid);
            break;
    }
} catch (Throwable $e) {
    error_log('[friends/action.php action] ' . $e->getMessage());
    $res = 'error';
}

/* email-сповіщення про нову заявку в друзі */
if ($do === 'send_friend' && $res === 'sent' && $shouldSendFriendRequestEmail) {
    try {
        if (function_exists('ntf_dispatch_friend_request')) {
            ntf_dispatch_friend_request(
                $pdo,
                $meId,
                $uid,
                $friendRequestIdForEmail
            );
        }
    } catch (Throwable $e) {
        error_log('[friends/action.php notify] ' . $e->getMessage());
    }
}

/* AJAX => JSON */
if ($isAjax) {
    $success = in_array($res, ['ok', 'sent', 'accepted', 'already_sent', 'already_friends', 'already', 'no', 'not_friends'], true);

    $sendJson([
        'ok'      => $success,
        'res'     => $res,
        'do'      => $do,
        'user_id' => $uid,
        'back'    => $back,
    ], 200);
}

/* HTML form => redirect назад */
$redirectBack($back, $res);