<?php

declare(strict_types=1);

namespace Tests\Integration;

use Tests\Support\DatabaseSeeder;
use Tests\Support\QdbTestCase;

final class ProgramSessionsTest extends QdbTestCase
{
    public function testAdminCrudAndMobileFetch(): void
    {
        $token = $this->adminToken();
        $qnId = $this->fixture()->questionnaireId;

        $create = $this->api()->request('POST', 'program_sessions', [
            'name' => 'Baseline',
            'description' => 'First visit',
            'sessionNumber' => 1,
            'orderIndex' => 0,
            'isActive' => true,
            'questionnaires' => [
                ['questionnaireID' => $qnId, 'orderIndex' => 0],
            ],
        ], ['Authorization' => 'Bearer ' . $token]);

        $this->assertApiOk($create);
        $sessionID = $create['data']['session']['sessionID'] ?? '';
        $this->assertNotSame('', $sessionID);
        $this->assertSame('Baseline', $create['data']['session']['name']);
        $this->assertCount(1, $create['data']['session']['questionnaires']);

        $list = $this->api()->request('GET', 'program_sessions', null, [
            'Authorization' => 'Bearer ' . $token,
        ]);
        $this->assertApiOk($list);
        $this->assertCount(1, $list['data']['sessions']);
        $this->assertFalse($list['data']['settings']['autoRepeatSessions'] ?? true);

        $update = $this->api()->request('PUT', 'program_sessions', [
            'sessionID' => $sessionID,
            'name' => 'Baseline updated',
            'sessionNumber' => 2,
            'questionnaires' => [],
        ], ['Authorization' => 'Bearer ' . $token]);
        $this->assertApiOk($update);
        $this->assertSame('Baseline updated', $update['data']['session']['name']);
        $this->assertSame([], $update['data']['session']['questionnaires']);

        $mobile = $this->coachMobileLogin();
        $appRes = $this->api()->request('GET', 'app_questionnaires', null, [
            'Authorization' => 'Bearer ' . $mobile['token'],
        ], ['sessions' => '1']);
        $this->assertApiOk($appRes);
        $this->assertCount(1, $appRes['data']['sessions']);
        $this->assertSame($sessionID, $appRes['data']['sessions'][0]['sessionID']);
        $this->assertArrayHasKey('settings', $appRes['data']);

        $delete = $this->api()->request('DELETE', 'program_sessions', [
            'sessionID' => $sessionID,
        ], ['Authorization' => 'Bearer ' . $token]);
        $this->assertApiOk($delete);

        $empty = $this->api()->request('GET', 'program_sessions', null, [
            'Authorization' => 'Bearer ' . $token,
        ]);
        $this->assertApiOk($empty);
        $this->assertSame([], $empty['data']['sessions']);
    }

    public function testAutoRepeatAdvancesCycleAfterLastSessionCompleted(): void
    {
        $adminToken = $this->adminToken();
        $qnId = $this->fixture()->questionnaireId;
        $clientCode = $this->fixture()->clientCode;

        $this->assertApiOk($this->api()->request('PATCH', 'program_sessions', [
            'autoRepeatSessions' => true,
        ], ['Authorization' => 'Bearer ' . $adminToken]));

        $session1 = $this->api()->request('POST', 'program_sessions', [
            'name' => 'Session 1',
            'sessionNumber' => 1,
            'orderIndex' => 0,
            'isActive' => true,
            'questionnaires' => [['questionnaireID' => $qnId, 'orderIndex' => 0]],
        ], ['Authorization' => 'Bearer ' . $adminToken]);
        $this->assertApiOk($session1);

        $session2 = $this->api()->request('POST', 'program_sessions', [
            'name' => 'Session 2',
            'sessionNumber' => 2,
            'orderIndex' => 1,
            'isActive' => true,
            'questionnaires' => [['questionnaireID' => $qnId, 'orderIndex' => 0]],
        ], ['Authorization' => 'Bearer ' . $adminToken]);
        $this->assertApiOk($session2);

        $login = $this->coachMobileLogin();
        $submit = $this->submitQuestionnaireAs(
            $login['token'],
            $qnId,
            $clientCode,
            [['questionID' => $this->fixture()->questionShortId, 'answerOptionKey' => 'yes']],
        );
        $this->assertApiOk($submit);
        $this->assertTrue($submit['data']['cycleAdvanced'] ?? false);
        $this->assertSame(2, $submit['data']['cycleNumber'] ?? 0);

        $clientsRes = $this->api()->withMobileToken($login['token'], 'GET', 'app_questionnaires', null, [
            'clients' => '1',
        ]);
        $this->assertApiOk($clientsRes);
        $plain = qdb_decrypt_sensitive_envelope($clientsRes['data'], $login['token']);
        $payload = json_decode($plain, true, 512, JSON_THROW_ON_ERROR);
        $client = null;
        foreach ($payload['clients'] as $row) {
            if (($row['clientCode'] ?? '') === $clientCode) {
                $client = $row;
                break;
            }
        }
        $this->assertNotNull($client);
        $progress = $client['programProgress'];
        $this->assertSame(2, $progress['cycleNumber']);
        $this->assertSame(2, $progress['totalSessions']);
        $this->assertSame(0, $progress['sessionsCompletedInCycle']);
        $this->assertTrue($progress['autoRepeatSessions']);
        $this->assertFalse($progress['programComplete']);
    }

    public function testAutoRepeatDisabledKeepsProgramComplete(): void
    {
        $adminToken = $this->adminToken();
        $qnId = $this->fixture()->questionnaireId;
        $clientCode = $this->fixture()->clientCode;

        $this->assertApiOk($this->api()->request('PATCH', 'program_sessions', [
            'autoRepeatSessions' => false,
        ], ['Authorization' => 'Bearer ' . $adminToken]));

        $this->assertApiOk($this->api()->request('POST', 'program_sessions', [
            'name' => 'Only session',
            'sessionNumber' => 1,
            'orderIndex' => 0,
            'isActive' => true,
            'questionnaires' => [['questionnaireID' => $qnId, 'orderIndex' => 0]],
        ], ['Authorization' => 'Bearer ' . $adminToken]));

        $login = $this->coachMobileLogin();
        $submit = $this->submitQuestionnaireAs(
            $login['token'],
            $qnId,
            $clientCode,
            [['questionID' => $this->fixture()->questionShortId, 'answerOptionKey' => 'yes']],
        );
        $this->assertApiOk($submit);
        $this->assertFalse($submit['data']['cycleAdvanced'] ?? true);
        $this->assertSame(1, $submit['data']['cycleNumber'] ?? 0);

        $clientsRes = $this->api()->withMobileToken($login['token'], 'GET', 'app_questionnaires', null, [
            'clients' => '1',
        ]);
        $this->assertApiOk($clientsRes);
        $plain = qdb_decrypt_sensitive_envelope($clientsRes['data'], $login['token']);
        $payload = json_decode($plain, true, 512, JSON_THROW_ON_ERROR);
        $progress = $payload['clients'][0]['programProgress'];
        $this->assertTrue($progress['cycleComplete']);
        $this->assertTrue($progress['programComplete']);
        $this->assertFalse($progress['autoRepeatSessions']);
    }

    public function testRejectUnknownQuestionnaire(): void
    {
        $token = $this->adminToken();
        $res = $this->api()->request('POST', 'program_sessions', [
            'name' => 'Invalid',
            'questionnaires' => [
                ['questionnaireID' => 'does-not-exist'],
            ],
        ], ['Authorization' => 'Bearer ' . $token]);
        $this->assertApiError($res, 'INVALID_FIELD', 400);
    }

    public function testCoachCannotCreateSession(): void
    {
        $mobile = $this->coachMobileLogin();
        $res = $this->api()->request('POST', 'program_sessions', [
            'name' => 'Blocked',
        ], ['Authorization' => 'Bearer ' . $mobile['token']]);
        $this->assertApiError($res, 'FORBIDDEN', 403);
    }
}
