<?php

namespace Tests\Unit\Mentorship;

use App\Http\Requests\Mentorship\SessionRequest;
use Tests\TestCase;

/**
 * Property-based tests for SessionRequest::prepareForValidation().
 *
 * Validates: Requirements 2.1, 2.4 (fix-checking), 3.1, 3.6 (preservation), 3.x (regression)
 */
class SessionRequestTest extends TestCase
{
    /**
     * Helper: build a SessionRequest, wire up the container, and invoke prepareForValidation().
     */
    private function makeRequest(array $data): SessionRequest
    {
        $request = SessionRequest::create('/test', 'POST', $data);
        $request->setContainer(app());
        $request->setRedirector(app(\Illuminate\Routing\Redirector::class));

        $reflection = new \ReflectionMethod(SessionRequest::class, 'prepareForValidation');
        $reflection->setAccessible(true);
        $reflection->invoke($request);

        return $request;
    }

    // -------------------------------------------------------------------------
    // Fix-checking tests (bug condition → correct output)
    // -------------------------------------------------------------------------

    /**
     * Validates: Requirements 2.1, 2.4
     * Bare HH:MM times must be combined with the date field before Carbon parsing.
     */
    public function test_combines_bare_hhmm_time_with_date(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-07-15',
            'start_time' => '09:00',
            'end_time'   => '10:30',
        ]);

        $this->assertSame('2025-07-15 09:00', $request->input('start_time'));
        $this->assertSame('2025-07-15 10:30', $request->input('end_time'));
        $this->assertSame(90, $request->input('duration_minutes'));
    }

    /**
     * Validates: Requirements 2.1, 2.4
     * Bare HH:MM:SS times (as some browsers emit) must also be combined with the date.
     */
    public function test_combines_bare_hhmmss_time_with_date(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-07-15',
            'start_time' => '09:00:00',
            'end_time'   => '10:30:00',
        ]);

        $this->assertStringContainsString('2025-07-15', $request->input('start_time'));
        $this->assertStringContainsString('2025-07-15', $request->input('end_time'));
        $this->assertSame(90, $request->input('duration_minutes'));
    }

    /**
     * Validates: Requirements 2.4
     * duration_minutes must be a positive integer for any valid session.
     */
    public function test_duration_is_positive_for_valid_session(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-12-01',
            'start_time' => '08:00',
            'end_time'   => '09:00',
        ]);

        $this->assertGreaterThan(0, $request->input('duration_minutes'));
    }

    /**
     * Validates: Requirements 2.4
     * A 15-minute session must produce duration_minutes = 15.
     */
    public function test_minimum_session_duration(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-07-15',
            'start_time' => '09:00',
            'end_time'   => '09:15',
        ]);

        $this->assertSame(15, $request->input('duration_minutes'));
    }

    /**
     * Validates: Requirements 2.4
     * An 8-hour session must produce duration_minutes = 480.
     */
    public function test_maximum_session_duration(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-07-15',
            'start_time' => '08:00',
            'end_time'   => '16:00',
        ]);

        $this->assertSame(480, $request->input('duration_minutes'));
    }

    // -------------------------------------------------------------------------
    // Preservation-checking tests (no bug condition → unchanged)
    // -------------------------------------------------------------------------

    /**
     * Validates: Requirements 3.6
     * Full datetime strings (reschedule form path) must pass through unmodified.
     */
    public function test_full_datetime_string_is_not_modified(): void
    {
        $request = $this->makeRequest([
            'start_time' => '2025-07-15 09:00:00',
            'end_time'   => '2025-07-15 10:30:00',
        ]);

        $this->assertSame('2025-07-15 09:00:00', $request->input('start_time'));
        $this->assertSame('2025-07-15 10:30:00', $request->input('end_time'));
        $this->assertSame(90, $request->input('duration_minutes'));
    }

    /**
     * Validates: Requirements 3.6
     * ISO 8601 datetime strings must pass through unmodified (T separator preserved).
     */
    public function test_iso_datetime_string_is_not_modified(): void
    {
        $request = $this->makeRequest([
            'start_time' => '2025-07-15T09:00:00',
            'end_time'   => '2025-07-15T10:30:00',
        ]);

        $this->assertStringContainsString('T', $request->input('start_time'));
        $this->assertSame(90, $request->input('duration_minutes'));
    }

    // -------------------------------------------------------------------------
    // Regression tests
    // -------------------------------------------------------------------------

    /**
     * Validates: Requirements 3.1
     * When no timezone is submitted, it must default to Africa/Kampala.
     */
    public function test_timezone_defaults_to_africa_kampala(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-07-15',
            'start_time' => '09:00',
            'end_time'   => '10:00',
        ]);

        $this->assertSame('Africa/Kampala', $request->input('timezone'));
    }

    /**
     * Validates: Requirements 3.1
     * An explicitly submitted timezone must be preserved as-is.
     */
    public function test_timezone_preserved_when_provided(): void
    {
        $request = $this->makeRequest([
            'date'       => '2025-07-15',
            'start_time' => '09:00',
            'end_time'   => '10:00',
            'timezone'   => 'UTC',
        ]);

        $this->assertSame('UTC', $request->input('timezone'));
    }

    /**
     * Validates: Requirements 2.4
     * When start_time or end_time are absent, duration_minutes must not be set.
     */
    public function test_duration_not_calculated_when_times_absent(): void
    {
        $request = $this->makeRequest([
            'date' => '2025-07-15',
        ]);

        $this->assertNull($request->input('duration_minutes'));
    }
}
