<?php

namespace App\Http\Controllers;

use App\Facades\Settings;
use App\Http\Resources\SalesChannelList;
use App\IntegrationRepository;
use App\Modules\Stock\AutoTraderStock;
use App\ReportTypes\VehicleReport;
use App\SalesChannelType;
use App\Services\AutoTraderHub;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\SalesChannelHistory;
use Mtc\MercuryDataModels\SalesChannelRule;
use Mtc\MercuryDataModels\Vehicle;

class SalesChannelController extends Controller
{
    public function index(IntegrationRepository $repository): SalesChannelList
    {
        return new SalesChannelList($repository->getEnabledForType('sales-channels'));
    }

    public function show(string $channel, IntegrationRepository $repository): array
    {
        $enabled = $repository->getEnabledForType('sales-channels');
        if (empty($enabled[$channel])) {
            abort(404);
        }

        return [
            'status' => null,
            'conditions' => $this->getConditionsForDisplay($channel),
            'data_options' => $this->getDataOptions(),
            'available_fields' => $this->getFieldTypes(),
            'name' => App::make($enabled[$channel]['class'])->name(),
            'channel' => $enabled[$channel],
            'logs' => SalesChannelHistory::query()
                ->where('channel', $channel)
                ->latest()
                ->take(50)
                ->get()
        ];
    }

    public function update(Request $request, string $channel)
    {
        SalesChannelRule::query()->updateOrCreate(
            [
                'channel' => $channel,
            ],
            [
                'conditions' => $this->getStorableConditions($request->input('conditions')),
            ]
        );
    }

    public function dealerships(string $channel): array
    {
        return Dealership::all()
            ->filter(fn(Dealership $dealership) => !empty($dealership->data['auto-trader-location-id']))
            ->groupBy(fn(Dealership $dealership) => $dealership->data['auto-trader-location-id'])
            ->map(fn($dealerships, $locationId) => [
                'id' => $dealerships->first()->id,
                'name' => $dealerships->pluck('name')->implode(' / '),
                'location_id' => $locationId,
            ])
            ->values()
            ->toArray();
    }

    public function locationStock(string $channel, string $locationId): array
    {
        return App::make(AutoTraderStock::class)->getStockStatusForLocation($locationId);
    }

    public function updatePublishAdvert(Request $request, string $channel): array
    {
        $request->validate([
            'vehicle_id' => 'required|integer|exists:vehicles,id',
            'publish_advert' => 'required|boolean',
        ]);

        $vehicle = Vehicle::query()
            ->with([
                'dealership', 'make', 'model', 'fuelType', 'drivetrain',
                'transmission', 'bodyStyle', 'mediaUses.media', 'features',
                'equipment', 'specs', 'autoTraderData',
            ])
            ->findOrFail($request->input('vehicle_id'));

        $vehicle->autoTraderData()->updateOrCreate(
            ['vehicle_id' => $vehicle->id],
            ['publish_advert' => $request->input('publish_advert')],
        );

        $vehicle->load('autoTraderData');

        $this->exportVehicleToHub($vehicle);

        return ['success' => true];
    }

    public function updatePublishProfile(Request $request, string $channel): array
    {
        $request->validate([
            'vehicle_id' => 'required|integer|exists:vehicles,id',
            'publish_profile' => 'required|boolean',
        ]);

        $vehicle = Vehicle::query()
            ->with([
                'dealership', 'make', 'model', 'fuelType', 'drivetrain',
                'transmission', 'bodyStyle', 'mediaUses.media', 'features',
                'equipment', 'specs', 'autoTraderData',
            ])
            ->findOrFail($request->input('vehicle_id'));

        $vehicle->autoTraderData()->updateOrCreate(
            ['vehicle_id' => $vehicle->id],
            ['publish_profile' => $request->input('publish_profile')],
        );

        $vehicle->load('autoTraderData');

        $this->exportVehicleToHub($vehicle);

        return ['success' => true];
    }

    private function exportVehicleToHub(Vehicle $vehicle): void
    {
        if (Settings::get('sales-channels-auto-trader-method') === 'ftp') {
            return;
        }

        $token = Settings::get('auto-trader-hub-token');
        if (!$token) {
            return;
        }

        try {
            App::make(AutoTraderHub::class)->setToken($token)->export($vehicle);
        } catch (\Exception $e) {
            Log::warning('Failed to export vehicle publish state to AutoTrader Hub', [
                'vehicle_id' => $vehicle->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    private function getStorableConditions(array $conditions): array
    {
        return collect($conditions)->map(function ($condition) {
            $condition['value'] = $condition['value']['operator'] == 'in'
                ? $this->convertConditionValueToArray($condition['value'])
                : $condition['value'];

            return $condition;
        })->toArray();
    }

    private function convertConditionValueToArray(array $value): array
    {
        $values = explode(',', (string) $value['value']);
        $values = collect($values)->map(fn($value) => trim($value))->toArray();
        $value['value'] = $values;
        return $value;
    }

    private function getConditionsForDisplay(string $channel): array
    {
        $conditions = SalesChannelRule::query()->where('channel', '=', $channel)->first()?->conditions;

        return collect($conditions)->map(function ($condition) {

            if ($condition['value']['operator'] == 'in' && is_array($condition['value']['value'])) {
                $condition['value']['value'] = implode(',', $condition['value']['value']);
            }

            return $condition;
        })->toArray();
    }

    private function getDataOptions(): array
    {
        return [
            'operators' => collect(config('reports.operators', []))
                ->map(fn ($type) => [
                    'id' => $type,
                    'name' => __('reports.operators.' . $type),
                ])->values(),
        ];
    }

    private function getFieldTypes(): array
    {
        return collect(App::make(VehicleReport::class)->columns())
            ->map(fn ($name, $id) => [
                'id' => $id,
                'name' => $name,
            ])->sortBy('name')->values()->toArray();
    }

    private function getCurrentStatus(string $channel): ?array
    {
        return match ($channel) {
            SalesChannelType::AUTOTRADER->value => App::make(AutoTraderStock::class)->getStockStatus(),
            default => null,
        };
    }
}
