<?php

namespace App;

use App\Http\Resources\OfferTileListResource;
use App\Http\Resources\VehicleListResource;
use App\Services\GraphService;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Mtc\MercuryDataModels\User;
use Mtc\MercuryDataModels\UserDashboardWidget;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleOffer;

class DashboardRepository
{
    protected static array $notForListingSites = [
        'popular-vehicles',
        'recent-vehicles'
    ];
    private Collection $userWidgets;

    public function __construct(private readonly GraphService $graphService, private readonly Request $request)
    {
    }

    public function load(User $user, string $section): array
    {
        if ($this->userHasSetWidgets($user, $section) === false) {
            $this->loadSectionDefaultLayout($section);
        }

        return $this->userWidgets
            ->map(fn ($widgetData) => $this->mapData($widgetData))
            ->toArray();
    }

    public function setForUser(User $user, array $widgets, string $section = 'home'): void
    {
        $user->dashboardWidgets()->delete();
        collect($widgets)
            ->filter(fn ($widget) => !empty($widget['widget']))
            ->each(fn ($widget, $index) => $user->dashboardWidgets()->create([
                'tenant_id' => tenant('id'),
                'section' => $section,
                'position' => $index,
                'kind' => $this->getWidgetKind($widget['widget']),
                'widget' => $widget['widget'],
                'data' => $widget['data'],
            ]));
    }

    public function getAvailable(User $user, string $section): array
    {
        //  in future filter by user roles and sections
        return collect(config('dashboard.widgets'))
            ->values()
            ->toArray();
    }

    private function userHasSetWidgets(User $user, string $section): bool
    {
        $this->userWidgets = $user->dashboardWidgets()
            ->where('section', $section)
            ->where('tenant_id', tenant('id'))
            ->get()
            ->keyBy('position');

        return $this->userWidgets->isNotEmpty();
    }

    private function loadSectionDefaultLayout(string $section)
    {
        match ($section) {
            'home' => $this->userWidgets = collect(config('dashboard.default_dashboard.home'))
                ->reject(fn ($item) => tenant('type') === 'listing'
                    && in_array($item['widget'], self::$notForListingSites))
                ->values(),
            default => $this->userWidgets = collect(),
        };
    }

    /**
     * Get vehicles with the most views in the past given number of days.
     *
     * @param int $days
     * @param int $limit
     * @return array
     */
    public function vehiclesByView(int $days = 7, int $limit = 5): array
    {
        return Vehicle::query()
            ->select(['title', 'derivative', 'registration_number', 'id'])
            ->withViewCount($days)
            ->active()
            ->with('mediaUses.media')
            ->orderBy('view_count', 'desc')
            ->limit($limit)
            ->get()
            ->toArray();
    }

    /**
     * Get vehicles with the most enquiries
     *
     * @param int $days
     * @param int $limit
     * @return array
     */
    public function vehiclesByEnquiries(int $days = 7, int $limit = 5): array
    {
        return Vehicle::query()
            ->select(['title', 'derivative', 'registration_number', 'id'])
            ->withEnquiryCount($days)
            ->with('mediaUses.media')
            ->orderBy('enquiry_count', 'desc')
            ->limit($limit)
            ->get()
            ->toArray();
    }

    /**
     * @return array
     */
    public function popularVehicles(): array
    {
        return [
            'views_7_days' => $this->vehiclesByView(),
            'views_30_days' => $this->vehiclesByView(30),
            'enquiries_7_days' => $this->vehiclesByEnquiries(),
            'enquiries_30_days' => $this->vehiclesByEnquiries(30),
        ];
    }

    public function mapData(UserDashboardWidget|array $widget)
    {
        $widget['data'] = match ($widget['widget']) {
            'popular-vehicles' => $this->popularVehicles(),
            'chart' => $this->loadChartData($widget['data']),
            'recent-vehicles', 'recent-offers' => $this->loadSection($widget['widget'], $widget['data'])
                ->toArray($this->request),
            default => $this->loadKPI($widget['widget'], $widget['data'])
        };
        return $widget;
    }

    public function loadChartData(mixed $data): array
    {
        return $this->graphService->getGraph($data);
    }

    private function loadSection(mixed $widget, mixed $data): JsonResource
    {
        return match ($widget) {
            'recent-offers' => new OfferTileListResource(
                VehicleOffer::query()
                    ->active()
                    ->with([
                        'make',
                        'model',
                        'mediaUses.media',
                    ])
                    ->latest()
                    ->take(4)
                    ->get()
            )->setThumbDimensions('square'),
            'recent-vehicles' => new VehicleListResource(
                Vehicle::query()
                    ->active()
                    ->with('mediaUses.media')
                    ->latest()
                    ->take(6)
                    ->get()
            ),
            'popular-vehicles' => $this->popularVehicles(),
        };
    }

    private function loadKPI(mixed $widget, mixed $data)
    {
        $widgetClass = config('reports.kpis.' . $widget);
        return $widgetClass ? App::make($widgetClass)->toArray() : [];
    }

    private function getWidgetKind(mixed $widget): string
    {
        return config("dashboard.widgets.$widget.kind");
    }
}
