<?php

namespace App\Http\Controllers\Hotel;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Carbon\Carbon;

use App\Models\Hotel\Season;

use App\Enums\Hotel\CycleType;

class SeasonController extends Controller
{
  //* Constructor
    public function __construct() {
        $this->middleware(['auth', 'role:administrador']);
    }

  //* Basic CRUD
    public function index() {
      //- Table Data
        if(request()->ajax()){
            return datatables()->of(Season::latest()->get())
                ->addColumn('s_name', function($data){
                    return ($data->id === 1)
                        ? __('seeders')['seasons'][$data->s_name] : $data->s_name;
                })
                ->addColumn('s_type', function($data){
                  // Cyclic
                    if ($data->is_cyclic) {
                        return '<i class="mr-1 fas fa-sync-alt"></i>'. __('neutral_words')['cyclic']
                            ."<br><small>{$data->cycle_type->label()}</small>";
                    }

                  // Defined
                    return '<i class="mr-1 far fa-calendar-alt"></i>'. __('neutral_words')['defined'];
                })
                ->addColumn('periods', function($data){
                    $periods = $data->s_periods['periods'] ?? [];
                    $has_many_periods = count($periods) > 5;
                    $periods = array_slice($periods, 0, 5);

                    $periods_structure = "";
                    if ($data->is_cyclic) { // Cyclic Seasons
                        switch ($data->cycle_type) {
                            case CycleType::WEEKLY:
                                $periods_structure = implode(
                                    ',<br>',
                                    array_map(function ($day) {
                                        return mb_strtoupper(
                                            Carbon::now()->startOfWeek(Carbon::SUNDAY)
                                                ->addDays($day)->translatedFormat('l')
                                        );
                                    }, $periods)
                                );
                                break;

                            case CycleType::CUSTOM:
                            default:
                                foreach ($periods as $period) {
                                    $dateFormat = __('neutral_words')['month_date_format'];

                                    $fromDate = mb_strtoupper(
                                        Carbon::createFromFormat('m-d', "{$period['from']['month']}-{$period['from']['day']}")
                                            ->isoFormat($dateFormat)
                                    );

                                    $toDate = mb_strtoupper(
                                        Carbon::createFromFormat('m-d', "{$period['to']['month']}-{$period['to']['day']}")
                                            ->isoFormat($dateFormat)
                                    );

                                    $periods_structure .= "{$fromDate} <b>⭢</b> {$toDate}<br>";
                                }
                                break;
                        }

                    } else { // Static Seasons
                        $periods_structure = implode(
                            '<br>',
                            array_map(
                                fn($period) => "{$period['from']} <b>⭢</b> {$period['to']}",
                                $periods
                            )
                        );
                    }
                        if ($has_many_periods) $periods_structure .= "<br><b>...</b>";

                    return $periods_structure;
                })
                ->addColumn('action', function($data){
                    if (in_array($data->id, [1]))  return; // Avoid Default Season

                    return "
                        <button type='button' name='edit' id='$data->id' class='px-0 btn-sm edit btn btn-primary fixed-width'>
                            <i class='fas fa-edit'></i>
                        </button>

                        <button type='button' name='delete' id='$data->id' class='px-0 delete btn btn-danger fixed-width'>
                            <i class='fas fa-trash-alt'></i>
                        </button>
                    ";
                })
                ->rawColumns(['action', 'periods', 's_type'])
                ->make(true);
        }

      //- View Data
        $cycle_types = CycleType::cases();

        return view('hotel.seasons.index', compact('cycle_types'));
    }

    public function store(Request $request) {
        // Create Record
        try {
            $form_data = $this->parseSeasonData($request);
            $season = Season::create($form_data);
        } catch (\Exception $e) {
            return response()->json([
                'error' => $e->getMessage(),
            ], 422); // 422 Unprocessable Entity
        }
        return response()->json(['success' => 'Registrado con éxito', 'id' => $season->id]);
    }

    public function edit($id) {
        if(request()->ajax()){
            $data = Season::findOrFail($id);
            return response()->json(['data' => $data]);
        }

        return view('errors.404');
    }

    public function update(Request $request) {
        // Avoid process if html form was modified
        if (count($request->period_from ?? []) !== count($request->period_to ?? []))
            return response()->json(['error' => 'Alteración de Campos Detectada'], 422);

        // Get RoomType to update
        $season = Season::findOrFail($request->hidden_id);

        // Update Record
        try {
            $form_data = $this->parseSeasonData($request);
            $season->update( $form_data);
        } catch (\Exception $e) {
            return response()->json([
                'error' => $e->getMessage(),
            ], 422); // 422 Unprocessable Entity
        }
        return response()->json(['success' => 'Actualizado con éxito']);
    }

    public function destroy($id) {
        $season_to_delete = Season::findOrFail($id);
        $season_to_delete->delete();
    }

  //* Support Functions
    private function parseSeasonData(Request $request): array {
        return array_filter([
            's_name'        => $request->s_name,
            'is_cyclic'     => $request->boolean('is_cyclic'),
            'cycle_type'    => $request->cycle_type,
            's_periods'     => $this->buildSeasonPeriods($request),  // Build Periods Structure
        ], fn ($value) => $value !== null); // Retrieves only non-null fields;
    }

    private function buildSeasonPeriods(Request $request): array {
      // Control Data
        $periods = [];
        $is_cyclic = $request->boolean('is_cyclic');
        $cycle_type = $request->enum('cycle_type', CycleType::class);

      // Parse with Cyclic Model
        if ($is_cyclic) { // Cyclic Seasons
            switch ($cycle_type) {
              // Semanal
                case CycleType::WEEKLY:
                    $periods = $request->period_days ?? [0];
                    sort($periods);
                    break;

              // Periodo Definido
                case CycleType::CUSTOM:
                default:
                  // Extract Data
                    $from_days   = $request->period_from_day ?? [];
                    $from_months = $request->period_from_month ?? [];
                    $to_days     = $request->period_to_day ?? [];
                    $to_months   = $request->period_to_month ?? [];

                  // Validations
                    if (
                        count($from_days)   !== count($from_months)
                        || count($from_days)   !== count($to_days)
                        || count($from_days)   !== count($to_months)
                    )
                        throw new \Exception("Alteración de Campos Detectadas");

                    if (empty($from_days))
                        throw new \Exception("Periodos de Temporada no especificados");

                  // Build Periods
                    $periods = array_map(
                        fn($fDay, $fMonth, $tDay, $tMonth) => [
                            'from' => [ 'month' => $fMonth, 'day'   => $fDay ],
                            'to' => [ 'month' => $tMonth, 'day'   => $tDay ],
                        ],
                        $from_days, $from_months,
                        $to_days, $to_months
                    );

                    break;
            }

        } else { // Static Seasons
          // Extract Data
            $from = $request->period_from ?? [];
            $to   = $request->period_to   ?? [];

          // Validations
            if (count($from) !== count($to))
                throw new \Exception("Alteración de Campos Detectadas");

            if (empty($from))
                throw new \Exception("Periodos de Temporada no especificados");

          // Build Periods
            $periods = array_map(
                fn($from, $to) => [ 'from' => $from, 'to'   => $to ],
                $from, $to
            );
        }

      // Return Parsed Periods
        return ['periods' => $periods];
    }

  //* Special Functions
    public function getOwnSeasons(){
        return Season::all()->except(1);
    }
}
