<?php

namespace App\Http\Resources;

use App\DealershipRepository;
use App\Events\LoadDealershipDataFields;
use App\Facades\Settings;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\App;
use Mtc\ContentManager\Contracts\MediaUse;
use Mtc\ContentManager\Http\Resources\MediaEntryResource;
use Mtc\ContentManager\Models\Template;
use Mtc\ContentManager\Traits\MapContentTrait;
use Mtc\Crm\Models\Form;
use Mtc\MercuryDataModels\Country;
use Mtc\MercuryDataModels\DealershipHoliday;
use Mtc\MercuryDataModels\Franchise;

class DealershipViewResource extends JsonResource
{
    use MapContentTrait;
    use SeoDataForModel;

    public static $wrap = '';

    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        $this->resource->load([
            'content.mediaUses.media',
            'content.subContent.mediaUses.media',
            'content.subContent.subContent.mediaUses.media',
            'content.subContent.subContent.subContent.mediaUses.media',
            'content.globalContent.contentElement.fields',
            'content.contentElement.fields',
            'content.subContent.contentElement.fields',
            'content.subContent.subContent.contentElement.fields',
            'content.subContent.subContent.subContent.contentElement.fields',
            'mediaUses.media',
            'departments',
        ]);

        $hasTimeZones = Settings::get('app-dealership-timezone');
        $this->loadDataFields();
        $dealership = $this->resource->toArray();
        $dealership['multiple_franchises'] = Settings::get('dealerships-multiple-franchises');
        $dealership['franchise_ids'] = $this->resource->franchises()->pluck('franchises.id');
        $dealership['media'] = $this->resource->mediaUses->pluck('media_id');
        $dealership['media_uses'] = $this->resource->mediaUses
            ->map(fn(MediaUse $mediaUse) => new MediaEntryResource($mediaUse));
        $dealership['holidays'] = $this->getHolidays();
        $dealership['open_times'] = $this->ensureOpenTimeFieldFormat('open_times');
        $dealership['coordinates'] = $this->coordinates();
        $dealership['seo'] = $this->getSeoData($this->resource);
        $dealership['alt_open_enabled'] = Settings::get('dealership-second-open-times');
        $dealership['alt_open_time_name'] = Settings::get('dealership-secondary-open-close-time-name');
        $dealership['structure_in_sync'] = $this->dealershipRepository()->isContentOutOfSync($this->resource) !== true;
        $dealership['content'] = $this->resource->content->map(fn ($content) => $this->mapContent($content));
        if ($dealership['alt_open_enabled']) {
            $dealership['alt_open_times'] = $this->ensureOpenTimeFieldFormat('alt_open_times');
        }
        $dealership['second_alt_open_enabled'] = Settings::get('dealership-third-open-times');
        $dealership['second_alt_open_time_name'] = Settings::get('dealership-tertiary-open-close-time-name');
        if ($dealership['second_alt_open_enabled']) {
            $dealership['second_alt_open_times'] = $this->ensureOpenTimeFieldFormat('second_alt_open_times');
        }
        $dealership['flags'] = [
            'timezone' => $hasTimeZones,
        ];

        return [
            'dealership' => $dealership,
            'countries' => Country::query()->select(['name', 'code'])->get(),
            'forms' => Form::query()->select(['name', 'id'])->get(),
            'franchises' => Franchise::query()->select(['name', 'id'])->orderBy('name')->get(),
            'templates' => Template::query()->active()->select('name', 'id')->get(),
            'timezones' => $hasTimeZones
                ? collect(\DateTimeZone::listIdentifiers())
                    ->map(fn($identifier) => [
                        'value' => $identifier,
                        'name' => $identifier
                    ])
                : [],
        ];
    }

    private function loadDataFields()
    {
        $this->resource->data_fields = collect(event(new LoadDealershipDataFields()))
            ->filter()
            ->mapWithKeys(fn($field) => $field)
            ->map(function ($field, $key) {
                $field['id'] = $key;
                return $field;
            })->values();

        $this->ensureDataHasFields();
    }

    private function ensureDataHasFields()
    {
        $data = $this->resource->data === null ? [] : $this->resource->data;

        foreach ($this->resource->data_fields as $field) {
            if (!isset($data[$field['id']])) {
                $data[$field['id']] = ($field['type'] === 'checkbox') ? false : '';
            }
        }

        $this->resource->data = $data;
    }

    private function ensureOpenTimeFieldFormat(string $field)
    {
        if (empty($this->resource[$field])) {
            return [
                ['dayOfWeek' => 1, 'open' => '', 'close' => ''],
                ['dayOfWeek' => 2, 'open' => '', 'close' => ''],
                ['dayOfWeek' => 3, 'open' => '', 'close' => ''],
                ['dayOfWeek' => 4, 'open' => '', 'close' => ''],
                ['dayOfWeek' => 5, 'open' => '', 'close' => ''],
                ['dayOfWeek' => 6, 'open' => '', 'close' => ''],
                ['dayOfWeek' => 7, 'open' => '', 'close' => ''],
            ];
        }
        return $this->resource[$field];
    }

    private function getHolidays()
    {
        return $this->resource->upcomingHolidays()
            ->get()
            ->map(fn (DealershipHoliday $holiday) => $holiday->date);
    }

    private function coordinates()
    {
        if (empty($this->resource->coordinates)) {
            return null;
        }
        $coordinates = explode(',', $this->resource->coordinates);

        return [
            'latLng' => $this->resource->coordinates ?? null,
            'lat' => $coordinates[0] ?? null,
            'lng' => $coordinates[1] ?? null,
        ];
    }

    private function dealershipRepository(): DealershipRepository
    {
        return App::make(DealershipRepository::class);
    }
}
