<?php

namespace Tests\Tenant\Controllers;

use App\Facades\Settings;
use App\Http\Controllers\FeedController;
use App\Http\Middleware\ApiAuthenticatedRequest;
use App\Http\Middleware\InitializeTenancyBySiteInRequest;
use Mtc\Crm\Models\Enquiry;
use Mtc\Crm\Models\EnquiryObject;
use Mtc\Crm\Models\Form;
use Mtc\Crm\Models\FormQuestion;
use Mtc\MercuryDataModels\Booking;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\VehicleReservations\Reservation;
use Tests\TenantTestCase;

class FeedControllerTest extends TenantTestCase
{

    private array $excludedMiddlewares = [
        InitializeTenancyBySiteInRequest::class,
        ApiAuthenticatedRequest::class,
    ];

    /**
     * Helper to setup Enquiry with related Vehicle, Form, Questions
     */
    private function createEnquiryWithVehicle(): Enquiry
    {
        $vehicle = Vehicle::factory()->create([
            'odometer_km' => 50000,
            'odometer_mi' => 31000,
        ]);
        $form = Form::factory()->create(['name' => 'Vehicle Enquiry']);
        $q1 = FormQuestion::factory()->create(['data' => ["ms-dynamics-field" => "first_name"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["ms-dynamics-field" => "last_name"]]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'reason_type' => 'vehicle',
            'reason_id' => $vehicle->id,
            'email' => 'carlover@example.com',
            'details' => [
                $q1->id => [
                    'answer' => 'Peter'
                ],
                $q2->id => [
                    'answer' => 'Parker'
                ],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                ]
            ]
        ]);

        EnquiryObject::factory()->create([
            'enquiry_id' => $enquiry->id,
            'object_type' => 'vehicle',
            'object_id' => $vehicle->id,
        ]);

        return $enquiry;
    }

    // --- STORM ENQUIRIES ENDPOINT TESTS ---

    public function testStormEnquiriesReturnsCorrectItems()
    {
        $enquiry = $this->createEnquiryWithVehicle();
        $booking = Booking::factory()->create(['uuid' => '1234567890']);
        $reservation = Reservation::factory()->create([]);

        $response = $this->withoutMiddleware($this->excludedMiddlewares)
            ->getJson(route('storm-enquiries', tenant('id')));
        $response->assertStatus(200);

        $json = $response->json();

        // Assert _meta
        $this->assertEquals(3, $json['_meta']['totalCount']);
        $this->assertEquals(15, $json['_meta']['perPage']);
        $this->assertEquals(1, $json['_meta']['pageCount']);
        $this->assertEquals(1, $json['_meta']['currentPage']);

        // Assert items
        $this->assertCount(3, $json['items']);
        foreach ($json['items'] as $item) {
            $this->assertArrayHasKey('_links', $item);
            $this->assertArrayHasKey('context', $item);
            $this->assertArrayHasKey('date_submitted', $item);
            $this->assertArrayHasKey('dealer', $item);
            $this->assertArrayHasKey('form', $item);
            $this->assertArrayHasKey('guid', $item);
            $this->assertArrayHasKey('type', $item);
        }

        // Assert order
        $dates = array_column($json['items'], 'date_submitted');
        $this->assertTrue($dates[0] >= $dates[1] && $dates[1] >= $dates[2]);

        // Assert type names
        $types = array_column($json['items'], 'type');
        $typeNames = array_column($types, 'name');
        $this->assertContains('Vehicle Enquiry', $typeNames);
        $this->assertContains('Vehicle Reservation', $typeNames);
        $this->assertContains('Service Booking', $typeNames);
    }

    public function testStormEnquiriesPaginationWorks()
    {
        Enquiry::factory()->count(20)->create();
        $response = $this->withoutMiddleware($this->excludedMiddlewares)
            ->getJson(route('storm-enquiries', tenant('id')) . '?page=2');
        $json = $response->json();

        $this->assertEquals(20, $json['_meta']['totalCount']);
        $this->assertEquals(15, $json['_meta']['perPage']);
        $this->assertEquals(2, $json['_meta']['pageCount']);
        $this->assertEquals(2, $json['_meta']['currentPage']);
        $this->assertCount(5, $json['items']);
    }

    public function testStormEnquiriesFilterByDateWorks()
    {
        Booking::factory()->create(['created_at' => now()->subDays(10), 'uuid' => '1234567890']);
        Reservation::factory()->create(['created_at' => now()->subDays(10)]);
        Enquiry::factory()->create(['created_at' => now()->subDays(10)]);

        $recentEnquiry = Enquiry::factory()->create(['created_at' => now()->subDays(1)]);

        $response = $this->withoutMiddleware($this->excludedMiddlewares)
            ->getJson(
                route('storm-enquiries', tenant('id')) .
                '?From=' . now()->subDays(2)->format('Y-m-d')
            );
        $json = $response->json();

        $this->assertCount(1, $json['items']);
        $this->assertEquals($recentEnquiry->id, $json['items'][0]['guid']);
    }

    public function testStormEnquiriesLinksRetainQueryParameters()
    {
        Enquiry::factory()->count(20)->create();

        $from = now()->subDays(5)->format('Y-m-d\TH:i:s');
        $to = now()->format('Y-m-d\TH:i:s');

        $response = $this->withoutMiddleware($this->excludedMiddlewares)
            ->getJson(
                route('storm-enquiries', tenant('id')) .
                '?From=' . $from . '&To=' . $to
            );

        $json = $response->json();

        $this->assertStringContainsString('From=' . urlencode($from), $json['_links']['self']);
        $this->assertStringContainsString('To=' . urlencode($to), $json['_links']['self']);
        $this->assertStringContainsString('From=' . urlencode($from), $json['_links']['first']);
        $this->assertStringContainsString('To=' . urlencode($to), $json['_links']['first']);
        $this->assertStringContainsString('From=' . urlencode($from), $json['_links']['last']);
        $this->assertStringContainsString('To=' . urlencode($to), $json['_links']['last']);

        if ($json['_links']['next']) {
            $this->assertStringContainsString('From=' . urlencode($from), $json['_links']['next']);
            $this->assertStringContainsString('To=' . urlencode($to), $json['_links']['next']);
        }
    }

    // ---  STORM ENQUIRY RESOURCE TESTS ---
    public function testStormEnquiryResourceEnquiry()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'distance measurement',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'km',
            'type' => 'string',
        ]);

        $enquiry = $this->createEnquiryWithVehicle();
        $controller = new FeedController();
        $response = $controller->stormEnquiry(request(), 'enquiry', $enquiry->id);

        $this->assertInstanceOf(\App\Http\Resources\StormEnquiryItemResource::class, $response);

        $data = $response->resolve();
        $this->assertEquals('Peter', $data['form']['customer']['first_name']);
        $this->assertEquals('Parker', $data['form']['customer']['last_name']);
        $this->assertEquals('Vehicle Enquiry', $data['type']['name']);
        $this->assertNotNull($data['context']['vehicle']);
        $this->assertEquals('km', $data['context']['vehicle']['odometer']['unit']);
        $this->assertEquals(50000, $data['context']['vehicle']['odometer']['current']);
    }

    public function testStormEnquiryResourceBooking()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'distance measurement',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'mi',
            'type' => 'string',
        ]);

        $booking = Booking::factory()->create([
            'uuid' => '123456',
            'mileage' => 15000,
            'registration_number' => 'ABC123',
        ]);

        $controller = new FeedController();
        $response = $controller->stormEnquiry(request(), 'booking', $booking->id);

        $this->assertInstanceOf(\App\Http\Resources\StormEnquiryItemResource::class, $response);

        $data = $response->resolve();
        $this->assertEquals('Service Booking', $data['type']['name']);
        $this->assertEquals('ABC123', $data['context']['vehicle']['vrm']);
        $this->assertEquals(15000, $data['context']['vehicle']['odometer']['current']);
        $this->assertEquals('mi', $data['context']['vehicle']['odometer']['unit']);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'distance measurement',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'km',
            'type' => 'string',
        ]);

        $responseKm = $controller->stormEnquiry(request(), 'booking', $booking->id);
        $dataKm = $responseKm->resolve();

        $this->assertEquals('km', $dataKm['context']['vehicle']['odometer']['unit']);
    }

    public function testStormEnquiryResourceReservation()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'distance measurement',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'km',
            'type' => 'string',
        ]);

        $vehicle = Vehicle::factory()->create([
            'odometer_km' => null,
            'odometer_mi' => 10000,
        ]);

        $reservation = Reservation::factory()->create([
            'amount' => 200,
            'vehicle_id' => $vehicle->id,
            'first_name' => 'John',
            'last_name' => 'Doe',
            'contact_number' => '1234567890',
            'email' => 'john@example.com',
        ]);

        $controller = new FeedController();
        $response = $controller->stormEnquiry(request(), 'reservation', $reservation->id);

        $this->assertInstanceOf(\App\Http\Resources\StormEnquiryItemResource::class, $response);

        $data = $response->resolve();
        $this->assertEquals('Vehicle Reservation', $data['type']['name']);
        $this->assertEquals(200, $data['form']['enquiry']['offer_price']);
        $this->assertEquals('John', $data['form']['customer']['first_name']);
        $this->assertEquals('Doe', $data['form']['customer']['last_name']);
        $this->assertEquals('km', $data['context']['vehicle']['odometer']['unit']);
        $this->assertEquals(16093, $data['context']['vehicle']['odometer']['current']);
    }

    public function testStormEnquiryNotFound()
    {
        $controller = new FeedController();
        $response = $controller->stormEnquiry(request(), 'enquiry', 99999);
        $this->assertEquals(404, $response->getStatusCode());
    }

    public function testStormEnquiryContactMethodsParsedCorrectly()
    {
        $vehicle = Vehicle::factory()->create();
        $form = Form::factory()->create(['name' => 'Contact Enquiry']);
        $q1 = FormQuestion::factory()->create(['data' => ['ms-dynamics-field' => 'first_name']]);
        $q2 = FormQuestion::factory()->create(['data' => ['ms-dynamics-field' => 'contact_methods']]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'details' => [
                $q1->id => ['answer' => 'Jane'],
                $q2->id => ['answer' => 'email,phone,sms'],
            ],
            'data' => [
                'questions' => [
                    $q1->id => ['component' => 'TextField', 'componentName' => 'TextField', 'meta' => null],
                    $q2->id => ['component' => 'TextField', 'componentName' => 'TextField', 'meta' => null],
                ],
            ],
        ]);

        EnquiryObject::factory()->create([
            'enquiry_id' => $enquiry->id,
            'object_type' => 'vehicle',
            'object_id' => $vehicle->id,
        ]);

        $controller = new FeedController();
        $response = $controller->stormEnquiry(request(), 'enquiry', $enquiry->id);
        $data = $response->resolve();

        $prefs = $data['form']['customer']['marketing_preferences']['first_party'];
        $this->assertTrue($prefs['email']);
        $this->assertTrue($prefs['phone']);
        $this->assertTrue($prefs['sms']);
        $this->assertFalse($prefs['post']);
    }

    public function testStormEnquiryEmptyContactMethodsDoesNotError()
    {
        $vehicle = Vehicle::factory()->create();
        $form = Form::factory()->create(['name' => 'Simple Enquiry']);
        $q1 = FormQuestion::factory()->create(['data' => ['ms-dynamics-field' => 'first_name']]);
        $q2 = FormQuestion::factory()->create(['data' => ['ms-dynamics-field' => 'contact_methods']]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'details' => [
                $q1->id => ['answer' => 'Jane'],
                $q2->id => ['answer' => ''],
            ],
            'data' => [
                'questions' => [
                    $q1->id => ['component' => 'TextField', 'componentName' => 'TextField', 'meta' => null],
                    $q2->id => ['component' => 'TextField', 'componentName' => 'TextField', 'meta' => null],
                ],
            ],
        ]);

        EnquiryObject::factory()->create([
            'enquiry_id' => $enquiry->id,
            'object_type' => 'vehicle',
            'object_id' => $vehicle->id,
        ]);

        $controller = new FeedController();
        $response = $controller->stormEnquiry(request(), 'enquiry', $enquiry->id);
        $data = $response->resolve();

        $prefs = $data['form']['customer']['marketing_preferences']['first_party'];
        $this->assertFalse($prefs['email']);
        $this->assertFalse($prefs['phone']);
        $this->assertFalse($prefs['sms']);
        $this->assertFalse($prefs['post']);
    }
}
