<?php

use App\Database\Seeds\DatabaseSeeder;
use CodeIgniter\Shield\Models\UserModel;
use CodeIgniter\Shield\Test\AuthenticationTesting;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\FeatureTestTrait;

/**
 * @internal
 */
final class EvaluationsFeatureTest extends CIUnitTestCase
{
    use AuthenticationTesting;
    use DatabaseTestTrait;
    use FeatureTestTrait;

    protected $migrate = true;
    protected $refresh = true;
    protected $seed = DatabaseSeeder::class;
    protected $DBGroup = 'tests';
    protected $namespace = ['CodeIgniter\\Shield', 'CodeIgniter\\Settings', 'App'];

    public function testCoachCanCreateFullEvaluationForOwnChild(): void
    {
        $coach   = $this->findUserByEmail('andrei@academia.local');
        $childId = (int) db_connect()->table('children')->select('id')->where('full_name', 'Luca Marin')->get()->getRowArray()['id'];

        $this->actingAs($coach);

        $create = $this->withSession($_SESSION)->post('/children/' . $childId . '/evaluations/full-evaluation', [
            'evaluation_date' => '2026-04-20',
            'evaluator_coach_id' => '',
            'notes' => 'Evaluare adaugata prin feature test.',
            'scores' => $this->scoresForType('full-evaluation', [
                'water-confidence' => '4.5',
                'breathing-control' => '4.4',
                'stroke-technique' => '4.6',
                'start-turn-basics' => '4.2',
                'race-awareness' => '4.1',
                'focus-effort' => '4.5',
            ]),
        ]);

        $create->assertRedirect();

        $evaluation = db_connect()
            ->table('evaluations e')
            ->select('e.*, types.slug')
            ->join('evaluation_types types', 'types.id = e.evaluation_type_id')
            ->where('e.child_id', $childId)
            ->where('e.evaluation_date', '2026-04-20')
            ->where('types.slug', 'full-evaluation')
            ->orderBy('e.id', 'DESC')
            ->get()
            ->getRowArray();

        $this->assertNotNull($evaluation);
        $this->assertSame('READY', $evaluation['final_status']);
        $this->assertSame(1, (int) $evaluation['promotion_signal']);
        $this->seeInDatabase('evaluation_status_history', [
            'evaluation_id' => $evaluation['id'],
            'new_status' => 'READY',
        ]);
        $this->seeInDatabase('journey_events', [
            'child_id' => $childId,
            'event_type' => 'evaluation_added',
        ]);

        $detail = $this->withSession($_SESSION)->get('/evaluations/' . $evaluation['id']);

        $detail->assertOK();
        $detail->assertSee('Luca Marin');
        $detail->assertSee('Semnal promovare');
    }

    public function testQuickCheckReadyDoesNotSetPromotionSignal(): void
    {
        $admin   = $this->findUserByEmail('admin@academia.local');
        $childId = (int) db_connect()->table('children')->select('id')->where('full_name', 'Maria Enache')->get()->getRowArray()['id'];

        $this->actingAs($admin);

        $create = $this->withSession($_SESSION)->post('/children/' . $childId . '/evaluations/quick-check', [
            'evaluation_date' => '2026-04-19',
            'evaluator_coach_id' => (string) db_connect()->table('coaches')->select('id')->where('full_name', 'Mihai Ionescu')->get()->getRowArray()['id'],
            'notes' => 'Quick Check READY, fara promovare automata.',
            'scores' => $this->scoresForType('quick-check', [
                'water-confidence' => '4.2',
                'breathing-control' => '4.1',
                'stroke-technique' => '4.3',
                'focus-effort' => '4.4',
            ]),
        ]);

        $create->assertRedirect();

        $evaluation = db_connect()
            ->table('evaluations e')
            ->select('e.*, types.slug')
            ->join('evaluation_types types', 'types.id = e.evaluation_type_id')
            ->where('e.child_id', $childId)
            ->where('e.evaluation_date', '2026-04-19')
            ->where('types.slug', 'quick-check')
            ->orderBy('e.id', 'DESC')
            ->get()
            ->getRowArray();

        $this->assertNotNull($evaluation);
        $this->assertSame('READY', $evaluation['final_status']);
        $this->assertSame(0, (int) $evaluation['promotion_signal']);
        $this->seeInDatabase('journey_events', [
            'child_id' => $childId,
            'event_type' => 'quick_check_added',
        ]);

        $profile = $this->withSession($_SESSION)->get('/children/' . $childId . '?tab=quick-checks');

        $profile->assertOK();
        $profile->assertSee('Quick Check READY, fara promovare automata.');
    }

    public function testCoachCannotEvaluateForeignChild(): void
    {
        $coach   = $this->findUserByEmail('andrei@academia.local');
        $childId = (int) db_connect()->table('children')->select('id')->where('full_name', 'Maria Enache')->get()->getRowArray()['id'];

        $this->actingAs($coach);

        $new = $this->withSession($_SESSION)->get('/children/' . $childId . '/evaluations/full-evaluation/new');
        $new->assertStatus(403);

        $create = $this->withSession($_SESSION)->post('/children/' . $childId . '/evaluations/full-evaluation', [
            'evaluation_date' => '2026-04-21',
            'notes' => 'Nu ar trebui salvata.',
            'scores' => [],
        ]);
        $create->assertStatus(403);
    }

    /**
     * @param array<string, string> $valuesBySlug
     * @return array<int, string>
     */
    private function scoresForType(string $typeSlug, array $valuesBySlug): array
    {
        $rows = db_connect()
            ->table('evaluation_type_criteria pivot')
            ->select('criteria.id, criteria.slug')
            ->join('evaluation_criteria criteria', 'criteria.id = pivot.evaluation_criteria_id')
            ->join('evaluation_types types', 'types.id = pivot.evaluation_type_id')
            ->where('types.slug', $typeSlug)
            ->orderBy('pivot.sort_order', 'ASC')
            ->get()
            ->getResultArray();

        $scores = [];
        foreach ($rows as $row) {
            $scores[(int) $row['id']] = $valuesBySlug[$row['slug']];
        }

        return $scores;
    }

    private function findUserByEmail(string $email)
    {
        return model(UserModel::class)->findByCredentials(['email' => $email]);
    }
}
