<?php

namespace App\Filament\Custom;

use App\Models\City;
use App\Models\Company;
use App\Models\Country;
use App\Models\Deductible;
use App\Models\Language;
use App\Models\Plan;
use App\Models\Price;
use App\Models\Province;
use Exception;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Notifications\Notification;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;
use Intervention\MimeSniffer\MimeSniffer;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;

class Create
{
    /**
     * @throws Exception
     */
    public static function city(): Select
    {
        return Select::make('city_id')
            ->label('City')
            ->placeholder('Please select a city')
            ->searchable()
            ->options(City::query()->orderBy('slug')->pluck('slug', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return City::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('slug', 'LIKE', "%$search%");
                    })
                    ->pluck('slug', 'id')
                    ->toArray();
            });
    }

    private static function filterTerm(string $search): string
    {
        return str_replace(['\\', '_', '%'], ['\\\\', '\\_', '\\%'], $search);
    }

    /**
     * @throws Exception
     */
    public static function company(): Select
    {
        return Select::make('company_id')
            ->label('Company')
            ->placeholder('Please select a company')
            ->searchable()
            ->options(Company::query()->orderBy('slug')->pluck('slug', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Company::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('slug', 'LIKE', "%$search%");
                    })
                    ->pluck('slug', 'id')
                    ->toArray();
            });
    }

    /**
     * @throws Exception
     */
    public static function country(): Select
    {
        return Select::make('country_id')
            ->label('Country')
            ->placeholder('Please select a country')
            ->searchable()
            ->options(Country::query()->orderBy('slug')->pluck('slug', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Country::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('slug', 'LIKE', "%$search%");
                    })
                    ->pluck('slug', 'id')
                    ->toArray();
            });
    }

    /**
     * @throws Exception
     */
    public static function deductible(): Select
    {
        return Select::make('deductible_id')
            ->label('Deductible')
            ->placeholder('Please select a deductible')
            ->searchable()
            ->options(Deductible::query()->orderBy('slug')->pluck('slug', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Deductible::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('slug', 'LIKE', "%$search%");
                    })
                    ->pluck('slug', 'id')
                    ->toArray();
            });
    }

    /**
     * @throws Exception
     */
    public static function image(string $column, string $folder): FileUpload
    {
        $formats = [
            'image/png',
            'image/jpeg',
            'image/jpg',
        ];
        return FileUpload::make($column)
            ->disk(config('filament.default_filesystem_disk'))
            ->image()
            ->imageEditor()
            ->imageEditorAspectRatios(['1:1'])
            ->imageEditorEmptyFillColor('#FFFFFF')
            ->acceptedFileTypes($formats)
            ->maxSize(config('app.max_file_size'))
            ->saveUploadedFileUsing(function (TemporaryUploadedFile $file, callable $set) use ($formats, $column, $folder) {
                $sniffer = MimeSniffer::createFromString($file->getContent());
                $type = $sniffer->getType();
                if (!in_array($type->name, $formats)) {
                    $message = "'$type->name' format is not supported.";
                    Notification::make('error')
                        ->danger()
                        ->title('File type not supported')
                        ->body($message)
                        ->send();
                    throw new Exception($message);
                }
                $path = $file->storeAs($folder . '/' . Str::ulid()->toString() . '.' . $file->extension());
                $set($column, $path);
                return $path;
            });
    }

    /**
     * @throws Exception
     */
    public static function language(): Select
    {
        return Select::make('language_id')
            ->label('Language')
            ->placeholder('Please select a language')
            ->searchable()
            ->options(Language::query()->orderBy('name')->pluck('name', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Language::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('name', 'LIKE', "%$search%");
                    })
                    ->pluck('name', 'id')
                    ->toArray();
            });
    }

    /**
     * @throws Exception
     */
    public static function plan(): Select
    {
        return Select::make('plan_id')
            ->label('Plan')
            ->placeholder('Please select a plan')
            ->searchable()
            ->options(Plan::query()->orderBy('slug')->pluck('slug', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Plan::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('slug', 'LIKE', "%$search%");
                    })
                    ->pluck('slug', 'id')
                    ->toArray();
            });
    }


    /**
     * @throws Exception
     */
    public static function price(): Select
    {
        return Select::make('price_id')
            ->label('Price')
            ->placeholder('Please select a price')
            ->searchable()
            ->options(Price::query()->whereNotNull('daily_cost')->orderBy('daily_cost')->pluck('daily_cost', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Price::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('daily_cost', 'LIKE', "%$search%");
                    })
                    ->pluck('daily_cost', 'id')
                    ->toArray();
            });
    }

    /**
     * @throws Exception
     */
    public static function province(): Select
    {
        return Select::make('province_id')
            ->label('Province')
            ->placeholder('Please select a province')
            ->searchable()
            ->options(Province::query()->orderBy('slug')->pluck('slug', 'id'))
            ->getSearchResultsUsing(function (string $search): array {
                return Province::query()
                    ->where(function (Builder $builder) use ($search) {
                        $search = self::filterTerm($search);
                        $builder->where('slug', 'LIKE', "%$search%");
                    })
                    ->pluck('slug', 'id')
                    ->toArray();
            });
    }
}
