<?php

namespace App\DataTables;

use App\Models\Evento;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\UploadedFile;
use Yajra\DataTables\DataTablesEditor;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class EventoDataTableEditor extends DataTablesEditor
{
  protected $model = Evento::class;

  /** Disco per le locandine (storage/app/public/eventi/...) */
  protected string $disk = 'eventi';

  protected string $uploadDir = ''; //'eventi';

  protected $messages = [
    'nome.required' => 'Il nome è richiesto',
    'descrizione.required' => 'La descrizione è richiesta',
    'data_inizio.required' => 'La data inizio è richiesta',
    'data_fine.required' => 'La data fine è richiesta',
    'apertura_prenotazione.required' => 'La data apertura prenotazione è richiesta',
    'chiusura_prenotazione.required' => 'La data chiusura prenotazione è richiesta',
    'prezzo_fisso.required' => 'Il prezzo fisso è richiesto',
    'prezzo.required' => 'Il prezzo è richiesto',
    'stato.required' => 'Il stato è richiesto',
    'note.required' => 'La note è richiesta',
    'is_attiva.required' => 'Indicare una delle due opzioni',
    'posti.required' => 'Il numero di posti è richiesto',
    'posti.integer' => 'Il numero di posti deve essere un numero intero',
    'copertina.required' => 'La copertina è richiesta',
    'copertina.string' => 'La copertina deve essere una stringa',
    'copertina.max' => 'La copertina deve essere lunga al massimo 2048 caratteri',
  ];

  /**
  * Get create action validation rules.
  *
  * @return array
  */
  public function createRules(): array
  {
    return [
      'nome'  => 'required',
      'descrizione' => 'nullable',
      'data_inizio' => 'required|date',
      'data_fine' => 'required|date',
      'apertura_prenotazione' => 'nullable|date',
      'chiusura_prenotazione' => 'nullable|date',
      'prezzo_fisso' => 'nullable|boolean',
      'prezzo' => 'nullable|numeric',
      'stato' => 'nullable|string',
      'note' => 'nullable',
      'immagine' => 'nullable|string|max:2048',
      'posti' => 'nullable|integer',
      'copertina' => 'nullable|string|max:2048',
    ];
  }

  public function createMessages(): array{
    return $this->messages;
  }

  /**
  * Get edit action validation rules.
  *
  * @param Model $model
  * @return array
  */
  public function editRules(Model $model): array
  {
    return [
      'nome'  => 'required',
      'descrizione' => 'nullable',
      'data_inizio' => 'required|date',
      'data_fine' => 'required|date',
      'apertura_prenotazione' => 'nullable|date',
      'chiusura_prenotazione' => 'nullable|date',
      'prezzo_fisso' => 'nullable|boolean',
      'prezzo' => 'nullable|numeric',
      'stato' => 'nullable|string',
      'note' => 'nullable',
      'immagine' => 'nullable|string|max:2048',
      'posti' => 'nullable|integer',
      'copertina' => 'nullable|string|max:2048',
    ];
  }

  public function editMessages(): array{
    return $this->messages;
  }

  /**
  * Get remove action validation rules.
  *
  * @param Model $model
  * @return array
  */
  public function removeRules(Model $model): array
  {
    return [];
  }

  public function creating(Model $model, array $data): array
  {
    // $model->roles()->sync([$data['ruolo_id']]);
    return $data;
  }

  public function updating(Model $model, array $data): array
  {
    // dd($data['ruolo']);
    // $model->roles()->sync([$data['ruolo_id']]);
    return $data;
  }

  /**
   * Dopo il salvataggio: se la locandina era in tmp (nuovo evento), spostala sotto eventi/{id}.
   */
  public function saved(Model $model, array $data): Model
  {
    if (! $model instanceof Evento) {
      return $model;
    }

    $path = $model->immagine;
    if (! is_string($path) || $path === '') {
      return $model;
    }

    $tmpPrefix = $this->uploadDir; //$this->uploadDir.'/tmp/';
    if (! str_starts_with($path, $tmpPrefix)) {
      return $model;
    }

    $storage = Storage::disk($this->disk);
    if (! $storage->exists($path)) {
      return $model;
    }

    $basename = basename($path);
    $destDir = $this->uploadDir.'/'.$model->getKey();
    $destPath = $destDir.'/'.$basename;

    $storage->makeDirectory($destDir);
    if ($storage->exists($destPath)) {
      $storage->delete($destPath);
    }
    $storage->move($path, $destPath);

    $model->immagine = $destPath;
    $model->saveQuietly();

    return $model;
  }

  public function messages(): array
  {
    return $this->messages;
  }

  /**
   * Regole validazione upload (campo Editor: immagine).
   */
  public function uploadRules(): array
  {
    return [
      'immagine' => ['required', 'file', 'image', 'mimes:jpeg,png,jpg,gif,webp', 'max:5120'],
    ];
  }

  public function upload(Request $request): JsonResponse
  {
    $this->action = 'upload';

    $field = $request->input('uploadField');
    if (! $field || ! is_string($field)) {
      $field = 'file';
    }

    try {
      $storage = Storage::disk($this->disk);
      $rules = $this->uploadRules();
      $fieldRules = ['upload' => $rules[$field] ?? []];

      $this->validate($request, $fieldRules, $this->messages(), $this->attributes());

      /** @var UploadedFile $uploadedFile */
      $uploadedFile = $request->file('upload');
      $directory = $this->resolveUploadDirectory($request);
      $filename = $this->getUploadedFilename($field, $uploadedFile);
      $id = $storage->putFileAs($directory, $uploadedFile, $filename);

      if (! is_string($id)) {
        throw ValidationException::withMessages([
          'upload' => 'Impossibile salvare il file caricato.',
        ]);
      }

      $id = $this->uploaded($id);

      return response()->json([
        'action' => $this->action,
        'data' => [],
        'files' => [
          'files' => [
            $id => [
              'filename' => $id,
              'original_name' => $uploadedFile->getClientOriginalName(),
              'size' => $uploadedFile->getSize(),
              'directory' => $directory,
              'disk' => $this->disk,
              'url' => $storage->url($id),
            ],
          ],
        ],
        'upload' => [
          'id' => $id,
        ],
      ]);
    } catch (ValidationException $exception) {
      return response()->json([
        'action' => $this->action,
        'data' => [],
        'fieldErrors' => [
          [
            'name' => $field,
            'status' => str_replace('upload', $field, (string) ($exception->errors()['upload'][0] ?? 'Errore di validazione')),
          ],
        ],
      ]);
    }
  }

  /**
   * Sottocartella per riga (edit) o temporanea per nuovo evento.
   */
  protected function resolveUploadDirectory(Request $request): string
  {
    $id = $request->input('id');
    if ($id !== null && $id !== '' && is_numeric($id)) {
      return $this->uploadDir.'/'.(int) $id;
    }

    return $this->uploadDir; //$this->uploadDir.'/tmp';
  }

  protected function getUploadedFilename(string $field, UploadedFile $uploadedFile): string
  {
    $ext = $uploadedFile->getClientOriginalExtension();

    return $field.'_'.time().'_'.Str::random(4).($ext !== '' ? '.'.$ext : '');
  }
}
