<?php

require_once __DIR__ . '/SegmentSeatAvailabilityBootstrap.php';

use App\Libraries\SegmentSeatAvailability;
use PHPUnit\Framework\TestCase;

/**
 * Route A→B→C→D→E→F (indices 0..5). Location IDs are letters for readability.
 *
 * @internal
 */
final class SegmentSeatAvailabilityTest extends TestCase
{
    /** @var list<string> */
    private array $stops = ['A', 'B', 'C', 'D', 'E', 'F'];

    public function testNoOverlapWhenSegmentsOnlyTouchAtHandoff(): void
    {
        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($this->stops, 'A', 'C', 'C', 'E'));
        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($this->stops, 'C', 'E', 'A', 'C'));
    }

    public function testNoOverlapAdjacentLegs(): void
    {
        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($this->stops, 'B', 'E', 'A', 'B'));
    }

    public function testOverlapWhenInnerSegmentInsideOuter(): void
    {
        $this->assertTrue(SegmentSeatAvailability::segmentsOverlap($this->stops, 'A', 'D', 'B', 'C'));
    }

    public function testOverlapWhenLongerSegmentContainsShorter(): void
    {
        $this->assertTrue(SegmentSeatAvailability::segmentsOverlap($this->stops, 'B', 'E', 'A', 'D'));
        $this->assertTrue(SegmentSeatAvailability::segmentsOverlap($this->stops, 'B', 'E', 'B', 'E'));
    }

    public function testNoOverlapWhenOnlyShareDropOfFirstWithPickOfSecond(): void
    {
        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($this->stops, 'B', 'E', 'A', 'B'));
    }

    public function testUnknownStopsDoNotOverlap(): void
    {
        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($this->stops, 'B', 'E', 'X', 'Y'));
        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($this->stops, 'B', 'B', 'A', 'C'));
    }

    public function testResolveBookingSegmentPrefersTicketPickDrop(): void
    {
        $segment = SegmentSeatAvailability::resolveBookingSegmentFromRow($this->stops, [
            'pick_location_id' => 'B',
            'drop_location_id' => 'D',
            'subtrip_pick_id' => 'A',
            'subtrip_drop_id' => 'F',
        ]);
        $this->assertSame(['pick' => 'B', 'drop' => 'D'], $segment);
    }

    public function testParseStoppageTrimsAndFilters(): void
    {
        $this->assertSame(['55', '41', '43'], SegmentSeatAvailability::parseStoppage(' 55, 41 ,,43 '));
    }

    /** Trip 75-style main stoppage: Cairo, Sharm, El Tor, Ras Sudr, … */
    public function testNoOverlapWhenLaterLegStartsWhereEarlierBookingEnds(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66'];

        $this->assertFalse(SegmentSeatAvailability::segmentsOverlap($stops, '54', '43', '32', '54'));
    }

    public function testOverlapWhenExistingBookingStoredWithReversedPickDrop(): void
    {
        $stops = ['32', '41', '43', '54'];

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlap($stops, '32', '41', '41', '32'));
    }

    public function testOverlapForNestedSegmentOnSameRoute(): void
    {
        $stops = ['32', '41', '43', '54'];

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlap($stops, '32', '41', '32', '43'));
    }

    /** Trip 75: Cairo→Sharm subtrip passes Ras Sudr / El Tor; blocks Ras Sudr→El Tor on same bus. */
    public function testPathOverlapCairoSharmBlocksRasSudrToElTor(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66', '67', '77', '78', '90', '55'];
        $cairoSharmStoppage = '32,43,54,66,67,78,41';
        $rasSudrTorStoppage = '54,43';

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '32',
            '41',
            $cairoSharmStoppage,
            '54',
            '43',
            $rasSudrTorStoppage
        ));
    }

    /** Trip 75: Cairo→Ras Sudr hands off at Ras Sudr; does not block Ras Sudr→El Tor. */
    public function testPathNoOverlapCairoRasSudrVsRasSudrToElTor(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66'];
        $cairoRasSudrStoppage = '32,43,54';

        $this->assertFalse(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '32',
            '54',
            $cairoRasSudrStoppage,
            '54',
            '43',
            '54,43'
        ));
    }

    /** Trip 75: identical Ras Sudr→El Tor segment must block the same seats. */
    public function testTrip75SameRasSudrToElTorSegmentOverlaps(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66', '67', '77', '78', '90', '55'];

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '54',
            '43',
            '54,43',
            '54',
            '43',
            '54,43'
        ));
    }

    /** Aug 5 Ras Sudr→El Tor: Cairo→El Tor seat 3 on same bus run blocks via subtrip path overlap. */
    public function testAug5RasSudrSearchBlocksCairoElTorSeatThree(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66', '67', '77', '78', '90', '55'];

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '54',
            '43',
            '54,43',
            '32',
            '43',
            '32,54,66,67,78,43'
        ));
    }

    /** Aug 5 Ras Sudr→El Tor: Cairo→Ras Sudr hands off at Ras Sudr — seat 6 stays free. */
    public function testAug5RasSudrSearchDoesNotBlockCairoRasSudrSeatSix(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66', '67', '77', '78', '90', '55'];

        $this->assertFalse(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '54',
            '43',
            '54,43',
            '32',
            '54',
            '32,66,54'
        ));
    }

    /** Trip 75 Aug 16/17 client scenario: Ras Sudr→El Tor search blocks Cairo→El Tor and Cairo→Sharm, not Cairo→Ras Sudr. */
    public function testAug17RasSudrSearchBlocksSeatsTwoAndFiveNotThree(): void
    {
        $stops = ['32', '41', '43', '54', '65', '66', '67', '77', '78', '90', '55'];
        $requestStoppage = '54,43';

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '54',
            '43',
            $requestStoppage,
            '32',
            '43',
            '32,54,66,67,78,43'
        ));

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '54',
            '43',
            $requestStoppage,
            '32',
            '41',
            '32,43,54,66,67,78,41'
        ));

        $this->assertFalse(SegmentSeatAvailability::segmentsOverlapWithPath(
            $stops,
            '54',
            '43',
            $requestStoppage,
            '32',
            '54',
            '32,66,54'
        ));
    }
}
