<?php

namespace App\Filament\Admin\Resources\OrderResource\Pages;

use App\Enums\IconEnum;
use App\Enums\InvoiceStatus;
use App\Enums\OrderAttributes;
use App\Enums\OrderStatus;
use App\Filament\Admin\Resources\InvoiceResource;
use App\Filament\Admin\Resources\OrderResource;
use App\Models\Invoice;
use App\Models\Order;
use App\Models\OrderProduct;
use App\Models\ProductService;
use App\Models\ProductSize;
use App\Models\ServiceFile;
use App\Models\ServiceType;
use Filament\Actions;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;

class EditOrder extends EditRecord
{
    protected static string $resource = OrderResource::class;

    public function getTitle(): string|Htmlable
    {
        return parent::getTitle().' '.$this->record->internal_po;
    }

    protected function mutateFormDataBeforeFill(array $data): array
    {
        $order = Order::findOrFail($data['id']);

        // Order Products
        foreach ($order->orderProducts as $key => $product) {
            $data['order_products'][$key] = [
                'sku'          => $product->sku,
                'product_name' => $product->product_name,
                'color'        => $product->color,
                'xs'           => $product->productSizes->where('size', 'xs')->first()->amount ?? null,
                's'            => $product->productSizes->where('size', 's')->first()->amount ?? null,
                'm'            => $product->productSizes->where('size', 'm')->first()->amount ?? null,
                'l'            => $product->productSizes->where('size', 'l')->first()->amount ?? null,
                'xl'           => $product->productSizes->where('size', 'xl')->first()->amount ?? null,
                '2xl'          => $product->productSizes->where('size', '2xl')->first()->amount ?? null,
                '3xl'          => $product->productSizes->where('size', '3xl')->first()->amount ?? null,
                'osfa'         => $product->productSizes->where('size', 'osfa')->first()->amount ?? null,
            ];
        }

        // Product Services
        foreach ($order->productServices as $key => $service) {
            $data['services'][$key] = [
                'placement'              => $service->placement ?? '',
                'amount'                 => $service->amount ?? '',
                'amount_price'           => $service->amount_price ?? '',
                'notes'                  => $service->notes ?? '',
                'serviceType'            => $service->serviceType->id ?? '',
                'serviceFileName'        => $service->serviceFile->name ?? '',
                'serviceFileWidth'       => $service->serviceFile->width ?? '',
                'serviceFileHeight'      => $service->serviceFile->height ?? '',
                'serviceFileCode'        => $service->serviceFile->code ?? '',
                'serviceFileSetupNumber' => $service->serviceFile->setup_number ?? '',
            ];
        }

        foreach (OrderAttributes::cases() as $case) {
            if ($data[$case->name]) {
                $data['order_attributes'][] = $case->value ?? null;
            }
        }

        return $data;
    }

    public function handleRecordUpdate(Model $record, array $data): Model
    {
        // Correctly set attribute booleans
        foreach (OrderAttributes::cases() as $case) {
            $data[$case->name] = false;
        }

        $data['order_attributes'] = array_filter($data['order_attributes']);

        foreach ($data['order_attributes'] as $attribute) {
            $data[OrderAttributes::from($attribute)->name] = true;
        }

        unset($data['order_attributes']);

        $record->update($data);

        // Delete old and create new Order Products
        foreach ($record->orderProducts as $product) {
            foreach ($product->productSizes as $size) {
                $size->delete();
            }

            $product->delete();
        }

        foreach ($data['order_products'] as $product) {
            $orderProduct = OrderProduct::create([
                'sku'          => $product['sku'],
                'product_name' => $product['product_name'],
                'color'        => $product['color'],
                'order_id'     => $record->id,
            ]);

            $sizes = ['xs', 's', 'm', 'l', 'xl', '2xl', '3xl', 'osfa'];

            foreach ($sizes as $size) {
                if ($product[$size] > 0) {
                    ProductSize::create([
                        'amount'           => $product[$size],
                        'size'             => $size,
                        'order_product_id' => $orderProduct->id,
                    ]);
                }
            }
        }

        // Delete old and create new services
        foreach ($record->productServices as $service) {
            $service->delete();
        }

        foreach ($data['services'] as $service) {
            $serviceFile = ServiceFile::create([
                'name'         => strtoupper($service['serviceFileName']) ?? '',
                'code'         => strtoupper($service['serviceFileCode']) ?? '',
                'width'        => $service['serviceFileWidth'] ?? null,
                'height'       => $service['serviceFileHeight'] ?? null,
                'setup_number' => $service['serviceFileSetupNumber'] ?? null,
            ]);

            ProductService::create([
                'service_type_id' => ServiceType::findOrFail($service['serviceType'])->id ?? null,
                'placement'       => strtoupper($service['placement']) ?? null,
                'notes'           => strtoupper($service['notes']) ?? null,
                'amount'          => $service['amount'] ?? null,
                'amount_price'    => $service['amount_price'] ?? null,
                'total_price'     => $service['total_price'] ?? null,
                'service_file_id' => $serviceFile->id,
                'order_id'        => $record->id,
            ]);
        }

        return $record;
    }

    protected function getHeaderActions(): array
    {
        return [
            Action::make('save')
                ->label('Save changes')
                ->action('save')
                ->icon(IconEnum::SAVE->value),

            Actions\ReplicateAction::make()
                ->label('Duplicate')
                ->icon(IconEnum::COPY->value)
                ->mutateRecordDataUsing(function (array $data): array {
                    $po                  = 'Duplicate of '.$data['customer_po'];
                    $data['customer_po'] = $po;

                    return $data;
                })
                ->beforeReplicaSaved(function (Order $replica): void {
                    $replica->customer_po    = 'Repeat of '.$replica->customer_po;
                    $replica->status         = OrderStatus::DRAFT;
                    $replica->printed        = false;
                    $replica->pre_production = false;
                    $replica->order_date     = today();
                    $replica->due_date       = today()->addDays(10);
                    $replica->save();

                    foreach ($this->record->orderProducts as $product) {
                        $newProduct           = $product->replicate();
                        $newProduct->order_id = $replica->id;
                        $newProduct->save();

                        foreach ($product->productSizes as $size) {
                            $newSize                   = $size->replicate();
                            $newSize->order_product_id = $newProduct->id;
                            $newSize->save();
                        }
                    }

                    /** @var ProductService $service */
                    foreach ($this->record->productServices as $service) {
                        /** @var ServiceFile $newServiceFile */
                        $newServiceFile = $service->serviceFile->replicate();

                        $newService                  = $service->replicate();
                        $newService->order_id        = $replica->id;
                        $newService->service_file_id = $newServiceFile->id;

                        $newService->save();
                    }
                })
                ->successRedirectUrl(fn (Model $replica): string => OrderResource::getUrl('edit', [$replica])),

            Action::make('invoice')
                ->visible(fn () => auth()->user()->is_admin)
                ->label(fn (Order $record) => $record->invoice()->exists() ? 'To Invoice' : 'Make Invoice')
                ->icon(IconEnum::INVOICE->value)
                ->action(function (Order $record) {
                    if ($record->invoice()->exists()) {
                        return redirect()->to(InvoiceResource::getUrl('edit', ['record' => $record->invoice->id]));
                    }

                    $invoice = Invoice::create([
                        'customer_id' => $record->customer_id,
                        'date'        => today(),
                        'status'      => InvoiceStatus::UNPAID->value,
                    ]);

                    $invoice->orders()->save($record);

                    return Notification::make()
                        ->title('Invoice '.$invoice->internal_id.' created successfully')
                        ->body('Click the button again to go to the invoice')
                        ->success()
                        ->send();
                }),

            Action::make('print')
                ->icon(IconEnum::PRINT->value)
                ->url(fn (Order $record) => route('orders.pdf', $record))
                ->openUrlInNewTab(),

            Actions\DeleteAction::make()
                ->icon(IconEnum::TRASH->value),
        ];
    }
}