<?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'
        ));
    }

    /** Client example: A(1,2,3) — B(4,6,5) — C(7); existing 3→5, search boards at 6 before 5. */
    public function testStandOverlapWhenBoardingBeforeExistingDrop(): void
    {
        $route = [
            ['id' => 1, 'stand_id' => 101],
            ['id' => 2, 'stand_id' => 102],
            ['id' => 3, 'stand_id' => 103],
            ['id' => 4, 'stand_id' => 104],
            ['id' => 6, 'stand_id' => 106],
            ['id' => 5, 'stand_id' => 105],
            ['id' => 7, 'stand_id' => 107],
        ];

        $this->assertTrue(SegmentSeatAvailability::segmentsOverlapOnPickdropRoute($route, 6, 7, 3, 5));
    }

    public function testStandNoOverlapWhenHandoffAtSamePickdrop(): void
    {
        $route = [
            ['id' => 1, 'stand_id' => 101],
            ['id' => 2, 'stand_id' => 102],
            ['id' => 3, 'stand_id' => 103],
            ['id' => 4, 'stand_id' => 104],
            ['id' => 6, 'stand_id' => 106],
            ['id' => 5, 'stand_id' => 105],
            ['id' => 7, 'stand_id' => 107],
        ];

        $this->assertFalse(SegmentSeatAvailability::segmentsOverlapOnPickdropRoute($route, 5, 7, 3, 5));
    }
}
