<?php

namespace Tests\Feature\Controllers\Api;

use App\Master\Models\ApiToken;
use App\Master\Models\ApiUserRoute;
use App\Models\ExportMap;
use Closure;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\DrivetrainType;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\OfferType;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleOffer;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\DatabaseTestCase;

class ExportMapApiControllerTest extends DatabaseTestCase
{
    public function test_download_requires_bearer_token()
    {
        tenant()->saveQuietly();
        $exportMap = ExportMap::factory()->withApiUrl()->create();

        $response = $this->getJson(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}"
        );

        $response->assertStatus(401);
    }

    public function test_download_returns_404_when_api_url_disabled()
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));
        ApiUserRoute::create([
            'api_user_id' => $apiToken->apiUser->id,
            'route_name' => 'tenant.exports.download',
        ]);

        $exportMap = ExportMap::factory()->create([
            'api_url_enabled' => false,
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer ' . $apiToken->token,
        ])->getJson(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}"
        );

        $response->assertStatus(404);
    }

    public function test_download_returns_404_when_inactive()
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));
        ApiUserRoute::create([
            'api_user_id' => $apiToken->apiUser->id,
            'route_name' => 'tenant.exports.download',
        ]);

        $exportMap = ExportMap::factory()->withApiUrl()->inactive()->create();

        $response = $this->withHeaders([
            'Authorization' => 'Bearer ' . $apiToken->token,
        ])->getJson(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}"
        );

        $response->assertStatus(404);
    }

    public function test_download_succeeds_with_valid_token()
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));
        ApiUserRoute::create([
            'api_user_id' => $apiToken->apiUser->id,
            'route_name' => 'tenant.exports.download',
        ]);

        $exportMap = ExportMap::factory()->withApiUrl()->create();

        $response = $this->withHeaders([
            'Authorization' => 'Bearer ' . $apiToken->token,
        ])->get(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}"
        );

        $response->assertStatus(200);

        // Verify last_downloaded_at was updated
        $exportMap->refresh();
        $this->assertNotNull($exportMap->last_downloaded_at);
    }

    public function test_download_succeeds_with_key_query_parameter()
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));
        ApiUserRoute::create([
            'api_user_id' => $apiToken->apiUser->id,
            'route_name' => 'tenant.exports.download',
        ]);

        $exportMap = ExportMap::factory()->withApiUrl()->create();

        $response = $this->get(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}?key={$apiToken->token}"
        );

        $response->assertStatus(200);
    }

    #[DataProvider('exportTypeProvider')]
    public function test_download_export_with_all_queryable_columns(string $type, Closure $createTestData)
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));
        ApiUserRoute::create([
            'api_user_id' => $apiToken->apiUser->id,
            'route_name' => 'tenant.exports.download',
        ]);

        $typeClass = config('export_maps.types.' . $type);
        $columns = array_keys(app($typeClass)->queryableColumns());

        $createTestData();

        $exportMap = ExportMap::factory()->withApiUrl()->forType($type)->create([
            'columns' => $columns,
            'headers' => $columns,
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer ' . $apiToken->token,
        ])->get(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}"
        );

        $response->assertStatus(200);
    }

    public function test_download_vehicle_export_with_json_data_column()
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));
        ApiUserRoute::create([
            'api_user_id' => $apiToken->apiUser->id,
            'route_name' => 'tenant.exports.download',
        ]);

        $dealership = Dealership::factory()->create();
        Vehicle::factory()->create([
            'dealership_id' => $dealership->id,
            'data' => ['car-gurus-dealership-id' => '12345'],
        ]);

        $exportMap = ExportMap::factory()->withApiUrl()->create([
            'columns' => ['uuid', 'data.car-gurus-dealership-id'],
            'headers' => ['UUID', 'CarGurus Dealership ID'],
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer ' . $apiToken->token,
        ])->get(
            "/api/exports/" . tenant('id') . "/{$exportMap->uuid}"
        );

        $response->assertStatus(200);
    }

    public static function exportTypeProvider(): array
    {
        return [
            'vehicle' => [
                'vehicle',
                function () {
                    $dealership = Dealership::factory()->create();
                    Vehicle::factory()->create(['dealership_id' => $dealership->id]);
                },
            ],
            'offer' => [
                'offer',
                function () {
                    $make = VehicleMake::factory()->create();
                    $model = VehicleModel::factory()->create(['make_id' => $make->id]);
                    $fuelType = FuelType::factory()->create();
                    $transmission = TransmissionType::factory()->create();
                    $bodyStyle = BodyStyleType::factory()->create();
                    $drivetrain = DrivetrainType::factory()->create();
                    $dealership = Dealership::factory()->create();
                    $franchise = Franchise::factory()->create();
                    $offerType = OfferType::factory()->create();

                    VehicleOffer::factory()->create([
                        'make_id' => $make->id,
                        'model_id' => $model->id,
                        'fuel_type_id' => $fuelType->id,
                        'transmission_id' => $transmission->id,
                        'body_style_id' => $bodyStyle->id,
                        'drivetrain_id' => $drivetrain->id,
                        'dealership_id' => $dealership->id,
                        'franchise_id' => $franchise->id,
                        'type_id' => $offerType->id,
                    ]);
                },
            ],
        ];
    }
}
