<?php

namespace App;

use App\Contracts\InteractsWithContentSync;
use App\Facades\Settings;
use App\Traits\RetrievesFieldData;
use App\Traits\SavesContent;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Mtc\ContentManager\Facades\Media;
use Mtc\ContentManager\Models\Template;
use Mtc\Crm\Models\Form;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\DealershipDepartment;
use Mtc\MercuryDataModels\DealershipHoliday;
use Mtc\MercuryDataModels\Franchise;
use Ramsey\Uuid\Uuid;

class DealershipRepository implements InteractsWithContentSync
{
    use RetrievesFieldData;
    use SavesContent;

    protected static array $dataFields = [
        'template_id',
    ];

    /**
     * Save Page
     *
     * @param Dealership $dealership
     * @param Request $request
     * @return void
     */
    public function saveContent(Dealership $dealership, Request $request)
    {
        $this->dropOrphanedContent($dealership, $this->getFlatContentElementIds($request->input('content')));

        collect($request->input('content'))
            ->each(fn ($element, $index) => $this->saveContentElement($dealership, $element, $index));
    }

    public function hasVersioning(): bool
    {
        return Settings::get('dealership-versioning-enabled') === true
            && TierHelper::isAllowed(tenant('tier'), Tier::STANDARD->value);
    }

    /**
     * Create a version snapshot for a bulk field change, mirroring the
     * inactive-snapshot the single-edit save writes. Snapshots the versioned
     * `data` fields ($dataFields) only; content is not re-snapshotted. When
     * $makeActive is true the snapshot becomes the active marker and any
     * previous active version is cleared.
     */
    public function saveBulkVersion(Dealership $dealership, int $author, bool $makeActive = false): void
    {
        if (!$this->hasVersioning()) {
            return;
        }

        if ($makeActive) {
            $dealership->versions()->update(['is_active' => false]);
        }

        $dealership->versions()->create([
            'uuid' => Uuid::uuid4(),
            'author_id' => $author,
            'is_active' => $makeActive,
            'data' => $dealership->only(self::$dataFields),
        ]);
    }

    public function importRecord(array $entry): bool
    {
        $departments = $entry['departments'] ?? [];
        $holidays = $entry['holidays'] ?? [];
        $franchiseSlugs = $entry['franchises'] ?? [];
        $mediaUrls = $entry['media_uses'] ?? [];

        $entry['franchise_id'] = !empty($entry['franchise'])
            ? Franchise::query()->where('slug', $entry['franchise'])->first()?->id
            : null;
        $entry['template_id'] = !empty($entry['template'])
            ? Template::query()->where('slug', $entry['template'])->first()?->id
            : null;
        $entry['contact_form_id'] = !empty($entry['contact_form'])
            ? Form::query()->where('name', $entry['contact_form'])->first()?->id
            : null;

        $dealership = Dealership::query()->create(Arr::only($entry, (new Dealership())->getFillable()));

        foreach ($departments as $department) {
            $department['dealership_id'] = $dealership->id;
            DealershipDepartment::query()->create(
                Arr::only($department, (new DealershipDepartment())->getFillable())
            );
        }

        foreach ($holidays as $holiday) {
            DealershipHoliday::query()->create([
                'dealership_id' => $dealership->id,
                'date' => $holiday['date'] ?? null,
                'note' => $holiday['note'] ?? null,
            ]);
        }

        if (!empty($franchiseSlugs)) {
            $franchiseIds = Franchise::query()
                ->whereIn('slug', $franchiseSlugs)
                ->pluck('id')
                ->toArray();
            if (!empty($franchiseIds)) {
                $dealership->franchises()->sync($franchiseIds);
            }
        }

        if (!empty($mediaUrls)) {
            $imageIds = [];
            foreach ($mediaUrls as $url) {
                $imageIds[] = Media::importImageFromUrl($url)->id;
            }
            Media::setUsesForModel($imageIds, $dealership);
        }

        return $dealership->exists;
    }

    public function canBeImported(array $entry): bool
    {
        return !Dealership::query()
            ->where('slug', $entry['slug'])
            ->exists();
    }

    public function exportToRemote(array $selections): array
    {
        return Dealership::query()
            ->with([
                'mediaUses.media',
                'departments',
                'upcomingHolidays',
                'franchise',
                'franchises',
                'template',
                'form',
            ])
            ->whereIn('id', $selections)
            ->get()
            ->map(function (Dealership $dealership) {
                $data = $dealership->toArray();

                $data['franchise'] = $dealership->franchise?->slug;
                $data['template'] = $dealership->template?->slug;
                $data['contact_form'] = $dealership->form?->name;
                unset($data['franchise_id'], $data['template_id'], $data['contact_form_id']);

                $data['franchises'] = $dealership->franchises->pluck('slug')->filter()->values()->toArray();

                $data['departments'] = $dealership->departments
                    ->map(fn (DealershipDepartment $department) => Arr::except(
                        Arr::only($department->toArray(), $department->getFillable()),
                        ['dealership_id']
                    ))
                    ->values()
                    ->toArray();

                $data['holidays'] = $dealership->upcomingHolidays
                    ->map(fn (DealershipHoliday $holiday) => [
                        'date' => $holiday->date,
                        'note' => $holiday->note,
                    ])
                    ->values()
                    ->toArray();

                $data['media_uses'] = $dealership->mediaUses
                    ->map(fn ($mediaUse) => $mediaUse->media?->getOriginalUrlAttribute())
                    ->filter()
                    ->values()
                    ->toArray();

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

    public function checkImportEntryValidity(array $dataEntry, array $allEntries): array
    {
        $errors = [];

        if (empty($dataEntry['slug'])) {
            $errors[] = __('validation.import_slug_missing', ['slug' => $dataEntry['slug']]);
        } elseif (Dealership::query()->where('slug', $dataEntry['slug'])->exists()) {
            $errors[] = __('validation.import_slug_taken', ['slug' => $dataEntry['slug']]);
        }

        return [
            'data' => $dataEntry,
            'errors' => $errors,
        ];
    }

    protected function elementParentColumnName(): string
    {
        return 'dealership_id';
    }

    protected function contentOwnerType(): string
    {
        return 'dealership-version';
    }

    protected function getQuery(): Builder
    {
        return Dealership::query();
    }
}
