<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
use App\Models\Level;
use App\Library\FinancialLib;

class ParkController extends Controller
{
    public function computeCost(Request $request) {
        try {
            $input = $request->input();
//            dd($input);
            
            // controllo se le ore di inizio e fine sosta scelte sono interne all'intervallo
            $livello = Level::with('area')->find($input['livello_id']);
            
            switch ($livello->tipo_sosta) {
                case 'std':
                    $dalle = Carbon::createFromFormat('H:i', $input['dalle_ore']);
                    $alle = Carbon::createFromFormat('H:i', $input['alle_ore']);

                    $now = Carbon::now();

                    $time = $now->format('H:i');
                    $ora = Carbon::createFromFormat('H:i', $time)->subMinutes(3);

                    if ($dalle < $ora) {
                        return json_encode([
                            'success'   => true,
                            'disable'   => true,
                            'content'   => html_entity_decode('La sosta non pu&ograve; iniziare prima delle ' . $ora->format('H:i')),
                        ]);
                    }

//                    if ($dalle >= $alle) {
//                        return json_encode([
//                            'success'   => true,
//                            'disable'   => true,
//                            'content'   => html_entity_decode("Orario selezionato errato."),
//                        ]);
//                    }
                    
                    $area = $livello->area;

                    $now = Carbon::now();

                    $inizio_pagamento = $now->format('Y-m-d') . ' ' . $area->ora_inizio_pagamento;
                    $fine_pagamento = $now->format('Y-m-d') . ' ' . $area->ora_fine_pagamento;

                    $inizio = Carbon::createFromFormat('Y-m-d H:i:s', $inizio_pagamento);
                    $fine = Carbon::createFromFormat('Y-m-d H:i:s', $fine_pagamento);
                    if (($dalle < $inizio) || ($alle > $fine)) {
                        return json_encode([
                            'success'   => true,
                            'disable'   => true,
                            'content'   => html_entity_decode("Uno o pi&ugrave; orari sono esterni al periodo a pagamento."),
                        ]);
                    }

                    $estensione = array_key_exists('estensione', $input);

                    try {
                        $dati_costo = $this->calcoloCosto($input, $estensione);
                    } catch (\Exception $e) {
                        return json_encode([
                            'success'   => true,
                            'disable'   => true,
                            'content'   => html_entity_decode("L'intervallo selezionato &egrave; interno ad un intervallo di non pagamento."),
                        ]);
                    }

                    return json_encode([
                        'success'   => true,
                        'disable'   => false,
                        'content'   => FinancialLib::centToEuro($dati_costo['c_fina'], false),
                    ]);
                    break;
                case 'gio':
                    $data_ora_gio_end = Carbon::createFromFormat('d/m/Y H:i:s', $input['data_sosta'] . ' ' . $input['dalle_ore'] . ':00')->addHours(24);
                    
                    $dati_costo = [
                        'c_fina'        => FinancialLib::centToEuro($livello->costo_fisso, false),
                        'data_ora_end'  => $data_ora_gio_end->format('H:i') . '  del  ' . $data_ora_gio_end->format('d/m/Y'),
                    ];
                    break;
                case 'fse':
                    $data_fse_end = Carbon::createFromFormat('d/m/Y', $input['data_sosta'])->addDays(2);
                    
                    $dati_costo = [
                        'c_fina'    => FinancialLib::centToEuro($livello->costo_fisso, false),
                        'data_end'  => $data_fse_end->format('d/m/Y'),
                    ];
                    
                    break;
                case 'set':
                    $data_set_end = Carbon::createFromFormat('d/m/Y', $input['data_sosta'])->addDays(6);
                    
                    $dati_costo = [
                        'c_fina'    => FinancialLib::centToEuro($livello->costo_fisso, false),
                        'data_end'  => $data_set_end->format('d/m/Y'),
                    ];
                    break;
                case 'men':
                    $data_men_end = Carbon::createFromFormat('d/m/Y', $input['data_sosta'])->addMonth()->subDay();
                    
                    $dati_costo = [
                        'c_fina'    => FinancialLib::centToEuro($livello->costo_fisso, false),
                        'data_end'  => $data_men_end->format('d/m/Y'),
                    ];
                    break;
            }

            return json_encode([
                'success'   => true,
                'disable'   => false,
                'content'   => $dati_costo,
            ]);
        } catch (\Exception $e) {
            if (config()->get('app.debug')) {
                dd($e);
            }
            
            return json_encode([
                'success'   => false,
                'disable'   => true,
                'content'   => '-',
            ]);
        }

    }
    
    private function calcoloCosto($input, $estensione = false) {
        $livello = Level::with('area')->find($input['livello_id']);
        
        if ($livello->tipo_sosta == 'std') {
            $area = $livello->area;

            $data_inizio = $input['data_sosta'];
            $data_fine = $input['data_sosta'];

            $inizio = Carbon::createFromFormat('H:i', $input['dalle_ore']);
            $fine = Carbon::createFromFormat('H:i', $input['alle_ore']);

            $o_i_p = Carbon::createFromFormat('H:i:s', $area->ora_inizio_pagamento);
            $o_f_p = Carbon::createFromFormat('H:i:s', $area->ora_fine_pagamento);

            if ($inizio < $o_i_p) {
                $input['dalle_ore'] = $o_i_p->format('H:i');
            }

            // determino se è prevista una chiusura intermedia
            $chiusura_intermedia = true;
            try {
                $o_i_c_i = Carbon::createFromFormat('H:i:s', $area->ora_inizio_chiusura_intermedia);
                $o_f_c_i = Carbon::createFromFormat('H:i:s', $area->ora_fine_chiusura_intermedia);
            } catch (\Exception $e) {
                $chiusura_intermedia = false;
            }

            // se è prevista una chiusura intermedia e l'ora di inizio e fine sosta sono rispettivamente
            // dopo e prima l'intervallo comunico che i dati immessi non sono validi
            if ($chiusura_intermedia && $inizio >= $o_i_c_i && $fine <= $o_f_c_i) {
                throw new \Exception();
            }

            // se è prevista una chiusura intermedia e l'ora di inizio sosta è impostata nell'intervallo di chiusura
            // sposto l'ora di inizio sosta a fine chiusura intermedia
            if ($chiusura_intermedia && $inizio > $o_i_c_i && $inizio <= $o_f_c_i) {
                $input['dalle_ore'] = $o_f_c_i->format('H:i');
            }

            // se è prevista una chiusura intermedia e l'ora di fine sosta è impostata nell'intervallo di chiusura
            // sposto l'ora di inizio sosta a fine chiusura intermedia
            if ($chiusura_intermedia && $fine > $o_i_c_i && $fine <= $o_f_c_i) {
                $input['alle_ore'] = $o_i_c_i->format('H:i');
            }

            // se è prevista una chiusura intermedia e l'ora di inizio e fine sosta sono rispettivamente
            // prima e dopo l'intervallo, decurto il periodo di chiusura dal periodo di sosta
            $decurta_chiusura_intermedia = false;
            if ($chiusura_intermedia && $inizio <= $o_i_c_i && $fine >= $o_f_c_i) {
                $decurta_chiusura_intermedia = true;
            }
    //        dd($decurta_chiusura_intermedia);

            $minuti_da_decurtare = 0;
            if ($decurta_chiusura_intermedia) {
                $minuti_da_decurtare = $o_f_c_i->diffInMinutes($o_i_c_i);
            }
    //        dd($minuti_da_decurtare);

            $t_i = Carbon::createFromFormat('d/m/Y H:i', $data_inizio . ' ' . $input['dalle_ore']);     // $t_i         inizio sosta
            $t_f = Carbon::createFromFormat('d/m/Y H:i', $data_fine . ' ' . $input['alle_ore']);        // $t_f         fine sosta

            // sposto in avanti l'inizio sosta per decurtare eventuali tempi iniziali a tariffa diversa da quella oraria
            $t_shift = $livello->tempo_gratuito;        // $t_shift     minuti di tempo a tariffa diversa da quella oraria

    //        dd($estensione);

            if ($estensione) {
                $t_shift = 0;
            }

            $t_i_shift = Carbon::createFromFormat('d/m/Y H:i', $data_inizio . ' ' . $input['dalle_ore'])->addMinutes($t_shift);

            $t_s = $t_f->diffInMinutes($t_i_shift);     // $t_s         Dt (tempo di sosta in minuti)

    //        dd($t_s . ' ' . $minuti_da_decurtare);
    //        dd($t_f->diffInMinutes($t_i) < $livello->tempo_gratuito);
    //        dd($t_f->diffInMinutes($t_i));

            if ($t_f->diffInMinutes($t_i) < $livello->tempo_gratuito && !$decurta_chiusura_intermedia) {
                $t_s = $livello->tempo_gratuito;
                $minuti_da_decurtare = $livello->tempo_gratuito;
            }
    //        dd($t_s . ' ' . $minuti_da_decurtare);

            $c_ini = $livello->costo_gratuito;          // $c_ini       costo iniziale

            if ($estensione) {
                $c_ini = 0;
                $t_s = $t_f->diffInMinutes($t_i);
                $minuti_da_decurtare = 0;
            }

            $c_o = $livello->tariffa_oraria;            // $c_o         costo orario

            $costo = $c_ini + (($c_o / 60) * ($t_s - $minuti_da_decurtare));

            $costo_approssimato = $this->approssima($costo);

            $rettifica = false;
            $costo_rettificato = 0;
            $t_f_rettificato = null;
            $t_s_rettificato = null;

            $c_max = $livello->costo_massimo;           // $c_max       costo massimo per la sosta
            $c_min = $livello->tariffa_minima;          // $c_min       costo minimo per la sosta

            // controllo se il costo della sosta supera il costo massimo (se impostato)
            if ($c_max > 0.00 && $costo_approssimato > $c_max) {
                $costo_rettificato = $c_max;
                $costo_approssimato = $this->approssima($costo_rettificato);

                $rettifica = true;
            }
            // controllo se il costo della sosta è minore del costo minimo (se impostato)
            else if ($c_min > 0.00 && $costo_approssimato < $c_min) {
                $costo_rettificato = $c_min;
                $costo_approssimato = $this->approssima($costo_rettificato);

                $rettifica = true;
            }

            if ($estensione) {
                $costo_rettificato = $costo_approssimato = $this->approssima($costo);
            }

    //        dd($costo_rettificato);

            // ricalcolo la durata e l'ora di fine della sosta per notificarlo all'utente
            if ($rettifica) {
                $t_s_rettificato = ($costo_rettificato - $c_ini) / ($c_o / 60);
                $t_f_rettificato = $t_i_shift->addMinutes($t_s_rettificato);
            }

            $costo_finale = $costo_rettificato > 0.00 ? $costo_rettificato : $costo_approssimato;

            $data = [
                't_i' => $t_i,
                't_i_shift' => $t_i_shift,
                't_f' => $t_f,
                't_f_rett' => $t_f_rettificato,
                't_s' => $t_s,
                't_s_rett' => $t_s_rettificato,
                'c_ini' => $c_ini,
                't_shift' => $t_shift,
                'c_o' => $c_o,
                'c_min' => $c_min,
                'c_max' => $c_max,
                'c' => $costo,
                'c_appr' => $costo_approssimato,
                'c_rett' => $costo_rettificato,
                'c_fina' => $costo_finale,
            ];
    //        dd($data);
        } else {
            $data = [
                'c_fina' => $livello->costo_fisso,
            ];
        }

        return $data;
    }
    
    private function approssima($costo) {
        $costo_approssimato = $costo;

        $parti = explode('.', $costo . '');

        if (count($parti) > 1) {
            $costo_approssimato = $parti[0] + 1;
        }

        return $costo_approssimato;
    }
}
