<?php

declare(strict_types=1);

if (PHP_SAPI !== 'cli') {
    http_response_code(403);
    exit(1);
}

require_once __DIR__ . '/../src/config.php';
require_once __DIR__ . '/../src/logger.php';
require_once __DIR__ . '/../src/storage.php';
require_once __DIR__ . '/../src/history.php';
require_once __DIR__ . '/../src/bitrix.php';
require_once __DIR__ . '/../src/crm.php';

$options = getopt('', ['dry-run', 'date::', 'help']);
if (isset($options['help'])) {
    echo "Usage: php tools/move_phone_only_deals.php [--dry-run] [--date=YYYY-MM-DD]\n";
    exit(0);
}

$timezone = new DateTimeZone((string) config('BUSINESS_TIMEZONE', 'Europe/Moscow'));
$targetDate = trim((string) ($options['date'] ?? ''));
if ($targetDate === '') {
    $targetDate = (new DateTimeImmutable('now', $timezone))->format('Y-m-d');
}
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $targetDate)) {
    fwrite(STDERR, "Invalid --date value. Expected YYYY-MM-DD.\n");
    exit(1);
}

$lockPath = dirname((string) config('STATE_FILE')) . '/phone_only_end_of_day.lock';
$lockHandle = fopen($lockPath, 'c');
if ($lockHandle === false) {
    fwrite(STDERR, 'Cannot open lock file: ' . $lockPath . PHP_EOL);
    exit(1);
}

if (!flock($lockHandle, LOCK_EX | LOCK_NB)) {
    echo json_encode([
        'ok' => true,
        'skipped' => 'Another phone-only process is already running.',
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
    exit(0);
}

$exitCode = 0;
try {
    $result = movePhoneOnlyDealsAtEndOfDay($targetDate, $timezone, isset($options['dry-run']));
    echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
    $exitCode = ($result['ok'] ?? false) ? 0 : 1;
} catch (Throwable $exception) {
    logMessage('error', 'Phone-only end-of-day processing failed', [
        'error' => $exception->getMessage(),
        'target_date' => $targetDate,
    ]);
    fwrite(STDERR, $exception->getMessage() . PHP_EOL);
    $exitCode = 1;
} finally {
    flock($lockHandle, LOCK_UN);
    fclose($lockHandle);
}

exit($exitCode);

function movePhoneOnlyDealsAtEndOfDay(string $targetDate, DateTimeZone $timezone, bool $dryRun): array
{
    if (!(bool) config('PHONE_ONLY_END_OF_DAY_ENABLED', true)) {
        return ['ok' => true, 'skipped' => 'Phone-only end-of-day processing disabled.'];
    }

    $history = listChatHistories();
    $chats = (array) ($history['chats'] ?? []);
    $phoneField = (string) config('DEAL_PHONE_FIELD', 'UF_CRM_1783332070432');
    $cityField = (string) config('DEAL_CITY_FIELD', 'UF_CRM_1693995123245');
    $categoryId = (string) config('PHONE_ONLY_END_OF_DAY_CATEGORY_ID', '0');
    $stageId = (string) config('PHONE_ONLY_END_OF_DAY_STAGE_ID', '44');
    $result = [
        'ok' => true,
        'dry_run' => $dryRun,
        'target_date' => $targetDate,
        'checked' => 0,
        'moved' => [],
        'skipped' => [],
    ];

    foreach ($chats as $chatKey => $chatValue) {
        $result['checked']++;
        $chat = (array) $chatValue;
        $context = (array) ($chat['context'] ?? []);
        $contact = (array) ($chat['contact'] ?? []);
        $phone = normalizePhoneForDeal((string) ($contact['phone'] ?? ''));
        $city = trim((string) ($contact['city'] ?? ''));

        if ($phone === '' || $city !== '') {
            $result['skipped'][] = ['chat' => $chatKey, 'reason' => 'not_phone_only'];
            continue;
        }

        if (trim((string) ($context['open_line_id'] ?? '')) === '') {
            $result['skipped'][] = ['chat' => $chatKey, 'reason' => 'not_open_line'];
            continue;
        }

        $processed = (array) ($chat['phone_only_end_of_day'] ?? []);
        if (trim((string) ($processed['phone'] ?? '')) === $phone
            && trim((string) ($processed['processed_at'] ?? '')) !== ''
        ) {
            $result['skipped'][] = ['chat' => $chatKey, 'reason' => 'already_processed'];
            continue;
        }

        $phoneReceivedAt = phoneReceivedAt($chat);
        if ($phoneReceivedAt === null || $phoneReceivedAt->setTimezone($timezone)->format('Y-m-d') !== $targetDate) {
            $result['skipped'][] = ['chat' => $chatKey, 'reason' => 'phone_received_on_another_date'];
            continue;
        }

        $dealId = normalizeCrmId($context['deal_id'] ?? '');
        if ($dealId === '') {
            $dealId = resolveDealIdFromOpenLineDialog($context);
        }
        if ($dealId === '') {
            $result['skipped'][] = ['chat' => $chatKey, 'reason' => 'deal_not_found'];
            continue;
        }

        $dealResponse = bitrixCall('crm.deal.get', ['id' => $dealId]);
        $deal = (array) ($dealResponse['result'] ?? []);
        if ((string) ($deal['CATEGORY_ID'] ?? '0') !== $categoryId) {
            $result['skipped'][] = ['chat' => $chatKey, 'deal_id' => $dealId, 'reason' => 'not_retail'];
            continue;
        }

        $dealPhone = $deal[$phoneField] ?? $phone;
        $dealCity = $deal[$cityField] ?? '';
        if (!dealFieldHasValue($dealPhone) || dealFieldHasValue($dealCity)) {
            $result['skipped'][] = ['chat' => $chatKey, 'deal_id' => $dealId, 'reason' => 'deal_is_not_phone_only'];
            continue;
        }

        if ((string) ($deal['STAGE_ID'] ?? '') === $stageId) {
            $crmResult = ['ok' => true, 'skipped' => 'Deal is already in the target stage.'];
        } elseif ($dryRun) {
            $crmResult = ['ok' => true, 'dry_run' => true, 'stage_id' => $stageId];
        } else {
            $crmResult = bitrixCall('crm.deal.update', [
                'id' => $dealId,
                'fields' => ['STAGE_ID' => $stageId],
            ]);
        }

        $item = [
            'chat' => $chatKey,
            'deal_id' => $dealId,
            'phone' => $phone,
            'stage_id' => $stageId,
            'result' => $crmResult,
        ];
        $result['moved'][] = $item;

        if (!$dryRun) {
            markPhoneOnlyEndOfDayProcessed((string) $chatKey, $dealId, $phone, $crmResult);
            logMessage('info', 'Phone-only deal moved at end of day', $item);
        }
    }

    return $result;
}

function phoneReceivedAt(array $chat): ?DateTimeImmutable
{
    $candidates = [
        $chat['contact_received_at']['phone'] ?? '',
        $chat['phone_workflow']['started_at'] ?? '',
        $chat['updated_at'] ?? '',
    ];

    foreach ($candidates as $candidate) {
        $candidate = trim((string) $candidate);
        if ($candidate === '') {
            continue;
        }

        try {
            return new DateTimeImmutable($candidate);
        } catch (Throwable $exception) {
            continue;
        }
    }

    return null;
}
