<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Ansapass;
use App\Models\PrepaidCard;
use App\Models\Workstation;
use App\Models\Takings;
use App\Models\Fare;
use App\Models\Turn;
use App\Models\PrepaidSummary;
use App\Models\Payment;

use App\Events\ProcessedAnsapass;
use App\Events\InsufficientFoundAnsapass;
use App\Events\DisabledAnsapass;
use App\Traits\PaginatorHelper;
use App\Jobs\SendChargePrepaidSmsJob;
use App\Jobs\CI4;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;

class AnsapassController extends Controller
{
    use PaginatorHelper;

    public function index(Request $request)
    {
        $helper = $this->processRequest($request);
        $ansapass = Ansapass::whereNotNull('id');
        $ansapass = $this->applyFilters($ansapass, $helper,
            ['code', 'prepaidCard.code', 'vehicle.plate']);

        return response()->json($ansapass);
    }

    public function readTag(Request $request)
    {
        // Recover the tag code readed
        $tagCode = strtoupper($request->tag);
        DB::beginTransaction();
        // Recover the only one workstation with radar reader
        $workstation = Workstation::where('name', '01')->first();

        try{
            // Try recover the ansapass asociated to that code
            $tag = Ansapass::with(['prepaidCard', 'vehicle'])
                            ->where('code', $tagCode)
                            ->first();

            // If the tag is not found, then return
            if(!$tag){
                return response()->json([
                    "status" => 0,
                    "date" => date('d/m/Y'),
                    "time" => date('H:i:s'),
                    "sticker" => $tagCode,
                    "info" => "No Registrado",
                    "user" => "---",
                    "balance" => "---"
                ]);
            }

            // Recover the prepaid card asociated to the tag
            $card = PrepaidCard::with('profile')->find($tag->prepaidCard->id);
            // Set temporal variables user and prepaid card code
            $info = new \stdClass();
            $info->id = $card->profile->id;
            $info->id_card = $card->profile->id_card;
            $info->user = $card->profile->names. " ".$card->profile->surnames;
            $info->prepaidCardCode = $card->code;
            $info->balance = $card->balance;

            // If the Ansapass is disbled
            if(!$tag->status){
                // Fire Event
                event(new DisabledAnsapass($workstation, $tag, $info));

                // Return
                return response()->json([
                    "status" => 0,
                    "date" => date('d/m/Y'),
                    "time" => date('H:i:s'),
                    "sticker" => $tagCode,
                    "info" => "Ansapass Deshabilitado",
                    "user" => $info->user,
                    "balance" => "---"
                ]);
            }

            // If the Ansapass was readed at least two minute ago
            $twoMinuteAgo = new \DateTime();
            $twoMinuteAgo->modify('-2 minutes');
            $charge = PrepaidSummary::where('created_at', '>', $twoMinuteAgo)
                                    ->where('ansapass_id', $tag->id)
                                    ->first();
            // If any charge was registered at least a minute ago, abort the operation
            if($charge){
                return response()->json([
                    "status" => 0,
                    "date" => date('d/m/Y'),
                    "time" => date('H:i:s'),
                    "sticker" => $tagCode,
                    "info" => "Cargo Realizado hace al menos 2 minutos",
                    "user" => "---",
                    "balance" => "---"
                ]);
            }

            // Recover the fare asocciated to the vehicle type
            $fare = Fare::where('vehicle_type_id', $tag->vehicle->vehicle_type_id)->orderBy('id', 'desc')->first();
            // If fare is not found, the return
            if(!$fare){
                return response()->json([
                    "status" => 0,
                    "date" => date('d/m/Y'),
                    "time" => date('H:i:s'),
                    "sticker" => $tagCode,
                    "info" => "Tarifa Invalida",
                    "user" => "---",
                    "balance" => "---"
                ]);
            }


            // If the balance is insuficcient, then return
            if($card->balance < $fare->value){
                // Fire Event
                event(new InsufficientFoundAnsapass($workstation, $tag, $info));
                // Return
                return response()->json([
                    "status" => 0,
                    "date" => date('d/m/Y'),
                    "time" => date('H:i:s'),
                    "sticker" => $tagCode,
                    "info" => "Saldo Insuficiente",
                    "user" => $info->user,
                    "balance" => $card->balance . " Bs."
                ]);
            }

            // Now debit 1 Bs from the card balance and save
            $card->balance -= $fare->value;
            $card->save();

            // Register a new Taking
            // First recover the last one turn in the island 01
            $lastTurn = Turn::with('profile')->where('workstation_id', $workstation->id)->orderBy('begin_at', 'desc')->first();
            // Now register a new Taking in that workstation
            $code = $this->generateTicketCode($lastTurn->profile->id);

            $ticket = Takings::create([
                'code' => $code,
                'turn_id' => $lastTurn->id,
                'vehicle_type_id' => $tag->vehicle->vehicle_type_id,
                'vehicle_id' => $tag->vehicle->id,
                'amount' =>  $card->exonerated ? 0 : $fare->value
            ]);

            // Save prepaid summay like an out
            $summary = PrepaidSummary::create([
                "prepaid_card_id" => $card->id,
                "ansapass_id" => $tag->id,
                "code" => $code,
                "type" => "out",
                "concept" => "Debito automatico en la caseta ". $workstation->name,
                "amount" =>  $card->exonerated  ? 0 : $fare->value,
                "new_balance" => $card->balance
            ]);

            // Save the payment in database
            $payment = Payment::create([
                "payment_method_id" => 6,
                "amount" =>  $card->exonerated ? 0 : $fare->value
            ]);

            // Attach the payment in both process
            $ticket->payments()->attach($payment);
            $summary->payments()->attach($payment);

            // Update balanace in info var
            $info->balance = $card->balance;

            SendChargePrepaidSmsJob::dispatch($card->profile, $summary);
            CI4::dispatch(["amount"=>$card->exonerated ? 0 : $fare->value,
                            "methodPay"=>"Carnet Prepagado",
                            "idClient"=>$info->id_card,
                            "client"=>$info->user,
                            "vin"=>$tag->vehicle->plate,
                            "vehicle"=>"",
                            "namePeaje"=>'Cardenalito',
                            "turn"=>$lastTurn->number,
                            "nameCollector"=>$lastTurn->profile->names,
                            "date"=>date("Y-m-d h:i:s"),
                            "typeVehicle"=>$fare->name,
                            "id_peaje"=>1]);

            // Block Proccess in cache
            Cache::put('blockAnsapass', true, 3);

            // Write in the database
            DB::commit();

            // Fire Event
            event(new ProcessedAnsapass($workstation, $tag, $info));

            // Return response
            return response()->json([
                "status" => 1,
                "date" => date('d/m/Y'),
                "time" => date('H:i:s'),
                "sticker" => $tagCode,
                "info" => "Carnet " . $info->prepaidCardCode,
                "user" => $info->user,
                "balance" => $info->balance . " Bs."
            ]);

        } catch(\Exception $e) {
            // Make a Rollback
            DB::rollback();
            \Log::debug($e);
            // Return Response
            return response()->json([
                "status" => 0,
                "date" => date('d/m/Y'),
                "time" => date('H:i:s'),
                "sticker" => $tagCode,
                "info" => "ERROR",
                "user" => "---",
                "balance" => "---"
            ]);
        }
    }

    public function create(Request $request)
    {
        $cardId = $request->cardId;
        $vehicleId = $request->vehicleId;
        $code = $request->code;

        try{
            if (!$code) {
                return response()->json([
                    "status" => 0,
                    "message" => "Debes proporcionar un codigo valido"
                ]);
            }

            if (strlen($code) > 30){
                $code = substr($code, 0, 30);
            }

            $tag = Ansapass::create([
                "prepaid_card_id" => $cardId,
                "vehicle_id" => $vehicleId,
                "code" => $code
            ]);

            return response()->json([
                "status" => 1,
                "message" => "Ansapass creado exitosamente",
                "item" => $tag
            ]);

        } catch(Exception $e) {
            return response()->json([
                "status" => 0,
                "message" => "Ocurrio un error, intente mas tarde"
            ]);
        }
    }

    public function delete(Request $request)
    {
        $id = $request->id;
        try{
            $ansapass = Ansapass::find($id);
            $ansapass->delete();
            return response()->json([
                "status" => 1,
                "message" => "Ansapass ". $ansapass->code . " eliminado exitosamente"
            ]);

        } catch (\Exception $e) {
            return response()->json([
                "status" => 0,
                "message" => "Ocurrio un error, intente mas tarde, si el problema persiste comuniquese con su administrador"
            ]);
        }
    }

    public function toggleStatus(Request $request)
    {
        $id = $request->id;
        try{
            $card = Ansapass::find($id);
            if(!$card){
                return response()->json([
                    "status" => 0,
                    "message" => "Ansapass No existe en la base de datos"
                ]);
            }

            $card->status = !$card->status;
            $card->save();
            return response()->json([
                "status" => 1,
                "message" => "Estatus del Ansapass ha sido cambiado exitosamente"
            ]);

        } catch (\Exception $e) {
            return response()->json([
                "status" => 0,
                "message" => "Ocurrio un error, intente mas tarde, si el problema persiste comuniquese con su administrador"
            ]);
        }
    }

    public function lastProcessed(Request $request)
    {
        $ansapass = Cache::get('lastAnsapassProcessed');
        return $ansapass;
    }

    private function generateTicketCode($operatorId): string
    {
        $id = sprintf('%03d', $operatorId);
        $code = microtime();
        $code = explode(' ', $code);
        $code = $code[1] . $id . $code[0];
        $code = str_replace(['0.', ''], '', $code);
        $code = substr($code, 0, -2);
        return $code;
    }
}
