<?php

namespace App\Filament\Resources\Manage\Journalists\Actions;

use App\Enums\DataChangeStatus;
use App\Enums\RoleEnum;
use App\Filament\Resources\Manage\DataChanges\DataChangesResource;
use App\Filament\Support\CheerfulNotification;
use App\Models\DataChangeRequest;
use App\Models\Journalist;
use App\Models\User;
use App\Notifications\BroadcastNotification;
use Filament\Actions\Action;
use Filament\Actions\EditAction;
use Filament\Support\Contracts\HasLabel;
use Filament\Support\Enums\Width;
use Illuminate\Support\Facades\Storage;

class EditJournalistAction extends EditAction
{
    protected function setUp(): void
    {
        parent::setUp();

        $this->modalWidth(Width::Large)
            ->successNotification(null)
            ->fillForm(function (Journalist $journalist): array {
                $data = $journalist->attributesToArray();

                $documents = [
                    'press_card_docs',
                    'ukw_certificate_docs',
                ];

                $mediaItems = $journalist->getMedia('journalists');

                foreach ($documents as $docField) {
                    $docType = str($docField)->replace('_docs', '')->slug('-');
                    $media = $mediaItems
                        ->where('custom_properties.doc_type', $docType)
                        ->sortByDesc('created_at')
                        ->first();

                    if ($media) {
                        $data[$docField] = [$media->getPathRelativeToRoot()];
                    }
                }

                return $data;
            })
            ->using(function (Journalist $record, array $data): Journalist {
                $user = auth()->user();

                if ($user->company?->verificationRequest !== null) {
                    $existingRequest = DataChangeRequest::where('entity_type', Journalist::class)
                        ->where('entity_id', $record->id)
                        ->where('status', DataChangeStatus::PENDING)
                        ->exists();

                    if ($existingRequest) {
                        CheerfulNotification::warning(
                            'Pengajuan Sudah Ada ⏳',
                            'Masih ada pengajuan perubahan data yang sedang menunggu verifikasi.'
                        )->send();

                        return $record;
                    }

                    $fieldLabels = Journalist::dataChangeEntryLabels();
                    $editableFields = ['name', 'email', 'phone_number', 'press_card', 'ukw_certificate'];

                    $changedFields = [];
                    $oldDataArr = [];

                    $casts = $record->getCasts();
                    foreach ($editableFields as $field) {
                        $val = $data[$field] ?? null;
                        $oldVal = $record->{$field};

                        // If value is a raw scalar but should be an enum, resolve it for display
                        if (isset($casts[$field]) && ! ($val instanceof \BackedEnum) && enum_exists($casts[$field])) {
                            $enumClass = $casts[$field];
                            $val = $enumClass::tryFrom($val) ?? $val;
                        }

                        $displayVal = ($val instanceof HasLabel) ? $val->getLabel() : ($val instanceof \BackedEnum ? $val->value : $val);
                        $displayOldVal = ($oldVal instanceof HasLabel) ? $oldVal->getLabel() : ($oldVal instanceof \BackedEnum ? $oldVal->value : $oldVal);

                        if ($displayOldVal !== $displayVal) {
                            $label = $fieldLabels[$field] ?? $field;
                            $changedFields[$label] = $displayVal;
                            $oldDataArr[$label] = $displayOldVal;
                        }
                    }

                    $documentFields = ['press_card_docs', 'ukw_certificate_docs'];
                    $mediaItems = $record->getMedia('journalists');

                    foreach ($documentFields as $field) {
                        $newDocs = array_values((array) ($data[$field] ?? []));
                        sort($newDocs);

                        $docType = str($field)->replace('_docs', '')->slug('-');
                        $currentMedia = $mediaItems
                            ->where('custom_properties.doc_type', $docType)
                            ->sortByDesc('created_at')
                            ->first();

                        $oldDocs = $currentMedia ? [$currentMedia->getPathRelativeToRoot()] : [];
                        $oldDocs = array_values($oldDocs);
                        sort($oldDocs);

                        if (json_encode($newDocs) !== json_encode($oldDocs)) {
                            $label = $fieldLabels[$field] ?? $field;
                            $changedFields[$label] = $newDocs;
                            $oldDataArr[$label] = $oldDocs;
                        }
                    }

                    if (empty($changedFields)) {
                        CheerfulNotification::info(
                            'Belum ada yang berubah ✨',
                            'Ubah data terlebih dulu lalu simpan kembali 💪'
                        )->send();

                        return $record;
                    }

                    $dataChangeRequest = DataChangeRequest::create([
                        'user_id' => auth()->id(),
                        'entity_type' => Journalist::class,
                        'entity_id' => $record->id,
                        'old_data' => $oldDataArr,
                        'new_data' => $changedFields,
                        'change_reason' => $data['change_reason'] ?? '-',
                    ]);

                    CheerfulNotification::success(
                        'Permohonan Berhasil 🎉',
                        'Data sudah dikirim dan sedang menunggu verifikasi admin ⏳'
                    )->send();

                    User::superAdmin()
                        ->get()
                        ->each(function ($admin) use ($dataChangeRequest, $user): void {
                            $admin->notify(new BroadcastNotification([
                                'title' => 'Ada Pengajuan Perubahan Jurnalis ✨',
                                'body' => 'Halooo Admin! 👋 '.$user->name.' baru saja mengajukan perubahan data jurnalis. Yuk, cek detailnya! 🚀',
                                'action' => [
                                    Action::make('view')
                                        ->label('Lihat')
                                        ->url(DataChangesResource::getUrl('view', ['record' => $dataChangeRequest->id])),
                                ],
                            ]));
                        });

                    return $record;
                }

                $this->performSave($record, $data);

                CheerfulNotification::update()->send();

                return $record;
            })
            ->visible(function (?Journalist $record): bool {
                $user = auth()->user();

                if (! $user->hasRole(RoleEnum::PERUSAHAAN->value)) {
                    return true;
                }

                if (! $user->company?->partnerMedia) {
                    return false;
                }

                return true;
            });
    }

    private function performSave(Journalist $record, array $data): void
    {
        $record->update([
            'name' => $data['name'],
            'email' => $data['email'],
            'phone_number' => $data['phone_number'],
            'press_card' => $data['press_card'],
            'ukw_certificate' => $data['ukw_certificate'],
        ]);

        $documents = [
            'press_card_docs',
            'ukw_certificate_docs',
        ];

        $existingMedia = $record->getMedia('journalists');
        $existingPaths = $existingMedia->map(fn ($m) => $m->getPathRelativeToRoot())->toArray();

        foreach ($documents as $field) {
            if (empty($data[$field])) {
                continue;
            }

            foreach ((array) $data[$field] as $filePath) {
                // If this path is already from one of our media items, skip re-adding it
                if (in_array($filePath, $existingPaths)) {
                    continue;
                }

                $fullPath = Storage::disk(config('filesystems.default'))->path($filePath);

                if (! file_exists($fullPath)) {
                    continue;
                }

                $record
                    ->addMediaFromDisk($filePath, config('filesystems.default'))
                    ->preservingOriginal()
                    ->withCustomProperties([
                        'feature' => 'journalists',
                        'date' => now()->toDateString(),
                        'doc_type' => str($field)
                            ->replace('_docs', '')
                            ->slug('-'),
                    ])
                    ->toMediaCollection('journalists');
            }
        }
    }
}
