<?php

namespace App\Http\Controllers;

use App\Http\Requests\RegisterRequest;
use App\Models\Log;
use App\Models\Register;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log as logFacades;

class RegisterController extends Controller
{
    public function index( Request $request ) : JsonResponse
    {
        $registers = Register ::when($request -> has('device_id') , function ( $query ) use ( $request ) {
            $query -> where('device_uuid' , $request['device_id']);
        }) -> get();
        $registers -> map(function ( $register ) {
            $register -> Translate();
        });
        return response() -> json([
            'status'  => 'success' ,
            'message' => 'Registers fetched successfully' ,
            'data'    => $registers ,
        ] , 200);
    }

    public function store( RegisterRequest $request ) : JsonResponse
    {
        DB ::beginTransaction();
        try {
            $register = new Register();
            $register -> title = $request['title'];
            $register -> device_uuid = $request['device_uuid'];
            $register -> unit = $request -> has('unit') ? $request['unit'] : null;
            $register -> type = $request -> has('type') ? $request['type'] : null;
            $register -> value = $request -> has('value') ? $request['value'] : null;
            $register -> save();
            DB ::commit();
            $register -> Translate();
            return response() -> json([
                'status'  => 'success' ,
                'data'    => $register ,
                'message' => __('register.created') ,
            ] , 200);
        } catch (\Exception $exception) {
            DB ::rollBack();
            return response() -> json([
                'status'  => 'error' ,
                'message' => $exception -> getMessage() ,
            ] , 500);
        }
    }

    public function show( Register $register ) : JsonResponse
    {
        $register -> Translate();
        return response() -> json([
            'status' => 'success' ,
            'data'   => $register ,
        ] , 200);
    }

    public function update( Register $register , RegisterRequest $request ) : JsonResponse
    {
        $url = rtrim(env('ADMIN_URL' , 'http://127.0.0.2:8001') , '/')."/registers/{$register->uuid}/fire";

        if ($request -> has('value') && $request['value'] == $register -> value) {
            return response() -> json([
                'status'  => 'error' ,
                'data'    => 'input value is the same as the current value' ,
                'message' => 'Error while updating register' ,
            ] , 422);
        }

        $device_uuid = $request['device_uuid'] ?? $register -> device_uuid;

        DB ::beginTransaction();
        try {
            // Update register
            $register -> device_uuid = $device_uuid;
            $register -> unit = $request -> has('unit') ? $request['unit'] : $register -> unit;
            $register -> type = $request -> has('type') ? $request['type'] : $register -> type;
            $register -> value = $request -> has('value') ? $request['value'] : $register -> value;
            $register -> set_at = Carbon ::now();
            $register -> save();

            DB ::commit();

            try {
                // Send async request
                $promise = Http ::timeout(5)
                    -> async()
                    -> post($url , [
                        'token' => Hash ::make('Register-'.$register -> uuid.'-Fire') ,
                    ]);

                $response = $promise -> wait();

                if ($response -> successful()) {
                    logFacades ::info("Register fired successfully: ".$response -> body());
                } else {
                    logFacades ::error("Failed to fire register: ".$response -> status().' - '.$response -> body());
                }
            } catch (\Throwable $httpException) {
                logFacades ::error("HTTP request to fire register failed: ".$httpException -> getMessage());
            }

            return response() -> json([
                'status'  => 'success' ,
                'data'    => $register ,
                'message' => __('register.updated') ,
            ] , 200);

        } catch (\Throwable $exception) {
            DB ::rollBack();

            logFacades ::error("Register update failed: ".$exception -> getMessage() , [
                'file' => $exception -> getFile() ,
                'line' => $exception -> getLine() ,
            ]);

            return response() -> json([
                'status'  => 'error' ,
                'message' => 'Server error: '.$exception -> getMessage() ,
            ] , 500);
        }
    }

    public function destroy( Register $register ) : JsonResponse
    {
        DB ::beginTransaction();
        try {
            $register -> delete();
            DB ::commit();
            return response() -> json([
                'status'  => 'success' ,
                'message' => __('register.deleted') ,
            ] , 200);
        } catch (\Exception $exception) {
            DB ::rollBack();
            return response() -> json([
                'status'  => 'error' ,
                'message' => $exception -> getMessage() ,
            ] , 500);
        }
    }

    public function logs( Register $register , Request $request )
    {
        $request -> validate([
            'pagination' => 'boolean' ,
            'from'       => 'required' ,
            'to'         => 'required' ,
        ]);
        $pagination = !$request -> has('pagination') || $request['pagination'];
        $from = $request -> has('from') && !is_null($request['from']) ? $request['from'] : null;
        $to = $request -> has('to') && !is_null($request['to']) ? $request['to'] : null;
        try {
            $logs = Log ::where('loggable_type' , Register::class) -> where('loggable_uuid' , $register -> uuid)
                -> when(!is_null($from) , function ( $query ) use ( $from ) {
                    $query -> whereDate('created_at' , '>=' , $from);
                }) -> when(!is_null($to) , function ( $query ) use ( $to ) {
                    $query -> whereDate('created_at' , '<=' , $to);
                }) -> orderBy('created_at' , 'DESC');
            if ($pagination) {
                $logs = $logs -> paginate(10);
            } else {
                $logs = $logs -> get();
            }
            return response() -> json([
                'status'  => 'success' ,
                'data'    => $logs ,
                'message' => 'Logs fetched successfully' ,
            ] , 200);
        } catch (\Exception $exception) {
            return response() -> json([
                'status'  => 'error' ,
                'data'    => $exception -> getMessage() ,
                'message' => 'Error while fetching logs' ,
            ] , 500);
        }
    }
}

