<?php

namespace App\Http\Controllers;

use App\Models\Item;
use App\Models\Line;
use App\Models\Machine;
use App\Models\MotorTestingMaster;
use App\Models\Plant;
use App\Models\TestingPanelReading;
use App\Models\WorkGroupMaster;
use DB;
use Filament\Notifications\Notification;
use Illuminate\Http\Request;
use Mpdf\Mpdf;
use chillerlan\QRCode\QROptions;
use chillerlan\QRCode\Output\QROutputInterface;
use Mpdf\QrCode\Output;
use Mpdf\QrCode\QrCode;
use Str;

class TestingPanelController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $expectedUser = env('API_AUTH_USER');
        $expectedPw   = env('API_AUTH_PW');

        $header_auth = $request->header('Authorization');
        $expectedToken = $expectedUser . ':' . $expectedPw;

        if ("Bearer " . $expectedToken != $header_auth)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Invalid authorization token!'
            ], 403);
        }

        $data = $request->all();

        if ($data['plant_code'] == null || $data['plant_code'] == '')
        {
            // return response("ERROR: Please provide a valid plant code.", 400)
            //     ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Plant code can't be empty!"
            ], 400);
        }
        else if (Str::length($data['plant_code']) < 4 || !is_numeric($data['plant_code']) || !preg_match('/^[1-9]\d{3,}$/', $data['plant_code']))//!ctype_digit($data['plant_code'])
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Invalid plant code found!"
            ], 400);
        }

        $plant = Plant::where('code', $data['plant_code'])->first();
        if (!$plant) {
            //return response("Plant not found.", 400)->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Plant not found!'
            ], 400);
        }

        $plantId = $plant->id;

        if ($data['line_name'] == null || $data['line_name'] == '')
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Group work center can't be empty!"
            ], 400);
        }
        else if (Str::length($data['line_name']) < 0)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Invalid group work center found!"
            ], 400);
        }

        $gWorkCenter = WorkGroupMaster::where('name', $data['line_name'])->first();
        if (!$gWorkCenter)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Group work center not found!'
            ], 400);
        }

        $gWorkCenter = WorkGroupMaster::where('name', $data['line_name'])->where('plant_id', $plantId)->first();
        if (!$gWorkCenter)
        {
            //return response(  "Line not found for the specified plant : {$data['plant_code']}",400)->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Group work center not found for the specified plant : '{$data['plant_code']}'!"
            ], 400);
        }

        $gWorkCenterId = $gWorkCenter->id;

        if ($data['machine_name'] == null || $data['machine_name'] == '')
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Work center can't be empty!"
            ], 400);
        }
        else if (Str::length($data['machine_name']) < 0)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Invalid work center found!"
            ], 400);
        }

        $machine = Machine::where('work_center', $data['machine_name'])->first();
        if (!$machine)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Work center not found!'
            ], 400);
        }

        $machine = Machine::where('work_center', $data['machine_name'])->where('plant_id', $plantId)->first();
        if (!$machine)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Work center not found for the specified plant : '{$data['plant_code']}'!"
            ], 400);
        }

        $machine = Machine::where('work_center', $data['machine_name'])->where('work_group_master_id', $gWorkCenterId)->first();
        if (!$machine)
        {
            // return response("Machine not found for the specified line : {$data['line_name']}", 400)->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Work center not found for the specified Group work center : '{$data['line_name']}'!"
            ], 400);

        }

        $machine = Machine::where('work_center', $data['machine_name'])->where('plant_id', $plantId)->where('work_group_master_id', $gWorkCenterId)->first();
        if (!$machine) {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Work center not found for the specified Plant : '{$data['plant_code']}' and Group work center : '{$data['line_name']}'!"
            ], 400);
        }

        $lineId = $machine->line_id;
        $machineId = $machine->id;

        try
        {
            $insertedSerials = [];
            $missedItemCodes = [];
            $duplicateItemCodes = [];
            $existSnoCount = [];

            if (!empty($data['item_codes']) && is_array($data['item_codes']))
            {
                foreach ($data['item_codes'] as $item)
                {
                    $code = $item['item_code'] ?? null;

                    // Check if item_code is present
                    if ($code == '' || $code == null)
                    {
                        return response()->json([
                            'status_code' => 'ERROR',
                            'status_description' => "Item code can't be empty!"
                        ], 400);
                    }

                    // Collect duplicates
                    if (isset($itemCodeCounts[$code]))
                    {
                        $itemCodeCounts[$code]++;
                        // Only add to duplicates array once
                        if ($itemCodeCounts[$code] == 2) {
                            $duplicateItemCodes[] = $code;
                        }
                    }
                    else
                    {
                        $itemCodeCounts[$code] = 1;
                    }

                    $motorTestingMaster = MotorTestingMaster::whereHas('item', function ($query) use ($item) {
                        $query->where('code', $item['item_code']);
                    })->where('plant_id', $plantId)->first();

                    if (!$motorTestingMaster) {
                        $missedItemCodes[] = $item['item_code'];
                    }

                    if (!empty($item['serial_numbers']) && is_array($item['serial_numbers'])) {
                        foreach ($item['serial_numbers'] as $serial)
                        {
                            $existSnoCount[] = $serial['serial_number'];
                        }
                    }
                }

                // If any duplicates found, return error
                if (!empty($duplicateItemCodes)) {
                    return response()->json([
                        'status_code' => 'ERROR',
                        'status_description' => 'Duplicate item codes found in request: ' . implode(', ', $duplicateItemCodes)
                    ], 400);
                }

                $uniqueInvalidCodes = array_unique($missedItemCodes);

                if (!empty($uniqueInvalidCodes)) {

                //    return response("Item codes : ". implode(', ', $uniqueInvalidCodes)." not found in motor testing master for the specified plant {$plant->name}", 400)
                //     ->header('Content-Type', 'text/plain');

                    return response()->json([
                        'status_code' => 'ERROR',
                        'status_description' => "Item codes : ". implode(', ', $uniqueInvalidCodes)." not found in master for the specified plant : '{$plant->name}'!"
                    ], 400);
                }

                $insertedSnoCount = [];

                foreach ($data['item_codes'] as $item)
                {

                    $motorTestingMaster = MotorTestingMaster::whereHas('item', callback: function ($query) use ($item) {
                        $query->where('code', $item['item_code']);
                    })->where('plant_id', $plantId)->first();

                    $motorTestingMasterId = $motorTestingMaster->id;

                    if (!empty($item['serial_numbers']) && is_array($item['serial_numbers']))
                    {
                        foreach ($item['serial_numbers'] as $serial)
                        {
                            //For update_count calculation
                            $updateCount = [
                                'plant_id'      => $plantId,
                                'line_id'       => $lineId,
                                'machine_id'    => $machineId,
                                'motor_testing_master_id' =>  $motorTestingMasterId,
                                'serial_number' => $serial['serial_number'] ?? null,
                                'rework_count'  => $serial['rework_count'] ?? 0,
                            ];

                            // // Find the current max update_count for this composite key //updated_at
                            // // $maxUpdateCount = \App\Models\TestingPanelReading::where($updateCount)->max('update_count');
                            // $maxUpdateCount = TestingPanelReading::where($updateCount)->orderByDesc('update_count')->select('update_count')->first();
                            //     // ->select(TestingPanelReading::raw('MAX(CAST(update_count AS INTEGER)) AS max_update_count'))->value('max_update_count');
                            //     // ->value('update_count')

                            // First, get the maximum length
                            $maxLength = TestingPanelReading::where($updateCount)->selectRaw('MAX(LENGTH(update_count)) as max_length')->value('max_length');

                            // Then, get all records with that length
                            $lastUpdateCount = TestingPanelReading::where($updateCount)->whereRaw('LENGTH(update_count) = ?', [$maxLength])->orderByDesc('update_count')->select('update_count')->first();//->get();

                            $newUpdateCount = ($lastUpdateCount == null || $lastUpdateCount == '') ? 0 : (int)$lastUpdateCount?->update_count + 1;//$maxUpdateCount?->update_count

                            $updateCountString = (string)$newUpdateCount;

                            $row = [
                                'plant_id'               => $plantId,
                                'line_id'                => $lineId,
                                'machine_id'             => $machineId,
                                'motor_testing_master_id'=> $motorTestingMasterId,
                                'serial_number'          => $serial['serial_number'] ?? null,
                                'winded_serial_number'   => $serial['winded_serial_number'] ?? null,
                                'output'                 => $serial['output'] ?? null,
                                'before_fr_volt'         => $serial['before_fr_volt'] ?? null,
                                'before_fr_cur'          => $serial['before_fr_cur'] ?? null,
                                'before_fr_pow'          => $serial['before_fr_pow'] ?? null,
                                'before_fr_res_ry'       => $serial['before_fr_res_ry'] ?? null,
                                'before_fr_res_yb'       => $serial['before_fr_res_yb'] ?? null,
                                'before_fr_res_br'       => $serial['before_fr_res_br'] ?? null,
                                'before_fr_ir'           => $serial['before_fr_ir'] ?? null,
                                'before_fr_ir_r'         => $serial['before_fr_ir_r'] ?? null,
                                'before_fr_ir_y'         => $serial['before_fr_ir_y'] ?? null,
                                'before_fr_ir_b'         => $serial['before_fr_ir_b'] ?? null,
                                'before_fr_freq'         => $serial['before_fr_freq'] ?? null,
                                'before_fr_speed'        => $serial['before_fr_speed'] ?? null,
                                'after_fr_vol'           => $serial['after_fr_vol'] ?? null,
                                'after_fr_cur'           => $serial['after_fr_cur'] ?? null,
                                'after_fr_pow'           => $serial['after_fr_pow'] ?? null,
                                'after_fr_ir_hot'        => $serial['after_fr_ir_hot'] ?? null,
                                'after_fr_ir_hot_r'      => $serial['after_fr_ir_hot_r'] ?? null,
                                'after_fr_ir_hot_y'      => $serial['after_fr_ir_hot_y'] ?? null,
                                'after_fr_ir_hot_b'      => $serial['after_fr_ir_hot_b'] ?? null,
                                'after_fr_ir_cool'       => $serial['after_fr_ir_cool'] ?? null,
                                'after_fr_ir_cool_r'     => $serial['after_fr_ir_cool_r'] ?? null,
                                'after_fr_ir_cool_y'     => $serial['after_fr_ir_cool_y'] ?? null,
                                'after_fr_ir_cool_b'     => $serial['after_fr_ir_cool_b'] ?? null,
                                'after_fr_freq'          => $serial['after_fr_freq'] ?? null,
                                'after_fr_speed'         => $serial['after_fr_speed'] ?? null,
                                'after_fr_leak_cur'      => $serial['after_fr_leak_cur'] ?? null,
                                'locked_rt_volt'         => $serial['locked_rt_volt'] ?? null,
                                'locked_rt_cur'          => $serial['locked_rt_cur'] ?? null,
                                'locked_rt_pow'          => $serial['locked_rt_pow'] ?? null,
                                'no_load_pickup_volt'    => $serial['no_load_pickup_volt'] ?? null,
                                'room_temperature'       => $serial['room_temperature'] ?? null,
                                'hv_test'                => $serial['hv_test'] ?? null,
                                'batch_number'           => $serial['batch_number'] ?? null,
                                'batch_count'            => $serial['batch_count'] ?? 0,
                                'result'                 => $serial['result'] ?? null,
                                'remark'                 => $serial['remark'] ?? null,
                                'rework_count'           => $serial['rework_count'] ?? 0,
                                'output_flag'            => $serial['output_flag'] ?? 0,
                                'tested_by'              => $serial['tested_by'] ?? null,
                                'updated_by'             => $serial['updated_by'] ?? null,
                                'created_at'             => $serial['created_at'] ?? null,
                                'updated_at'             => $serial['updated_at'] ?? $serial['created_at'],
                                'scanned_at'             => $serial['scanned_at'] ?? null,
                                'update_count'           => $updateCountString,
                            ];

                            // Insert the new record
                            TestingPanelReading::create($row);
                            $insertedSerials[] = $serial['serial_number'] ?? '[unknown]';
                            $insertedSnoCount[] = $serial['serial_number'];
                        }
                    }
                }
            }

            if (!empty($insertedSerials))
            {
                if(count($existSnoCount) == count($insertedSnoCount))
                {
                    // $messages[] = "Inserted serial numbers are: " . implode(', ', $insertedSerials);
                    return response()->json([
                        'status_code' => 'SUCCESS',
                        'status_description' => 'Inserted serial numbers are: ' . implode(', ', $insertedSerials)
                    ], 200);
                }
                else
                {
                    $missingSno = array_diff($existSnoCount,$insertedSnoCount);
                    return response()->json([
                        'status_code' => 'ERROR',
                        'status_description' => "Missed serial numbers are: " . implode(', ', $missingSno)
                    ], 400);
                }
            }
        }
        catch (\Exception $e)
        {
            // return response($e->getMessage(), 500)->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Store testing panel readings internal server error : '.$e?->getCode()
            ], 500);
        }
    }

    /**
     * Display the specified resource.
     */
    public function get_motor_master(Request $request)
    {
        $expectedUser = env('API_AUTH_USER');
        $expectedPw   = env('API_AUTH_PW');
        $header_auth  = $request->header('Authorization');
        $expectedToken = $expectedUser . ':' . $expectedPw;

        //$data = $request->all();
        if ("Bearer " . $expectedToken != $header_auth)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Invalid authorization token!'
            ], 403);
        }

        $plantCode = $request->header('plant-code');
        $itemCode = $request->header('item-code');
        // $description = $item ? $item->description : '';

        if ($plantCode == null || $plantCode == '')
        {
            // return response("ERROR: Plant Name can't be empty", 400)
            //     ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Plant code can't be empty!"
            ], 400);
        }
        else if (Str::length($plantCode) < 4 || !is_numeric($plantCode) || !preg_match('/^[1-9]\d{3,}$/', $plantCode))
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Invalid plant code found!"
            ], 400);
        }
        else if($itemCode == null || $itemCode == '')
        {
            // return response("ERROR: OBD Number can't be empty", 400)
            // ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Item Code can't be empty!"
            ], 400);
        }
        else if(Str::length($itemCode) < 6 || !ctype_alnum($itemCode))
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Invalid item code found!"
            ], 400);
        }

        $plant = Plant::where('code', $plantCode)->first();

        if (!$plant) {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Plant not found!"
            ], 400);
        }

        $plantId = $plant->id;

        $item = Item::where('code', $itemCode)->first();

        if (!$item)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Item Code not found in item table!"
            ], 404);
        }

        $item = Item::where('plant_id', $plantId)->where('code', $itemCode)->first();

        if (!$item)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Item Code not found in item table for the plant : '$plant->name'!"
            ], 404);
        }

        // Get description or empty string if not found
        $description = $item ? $item->description : '';

        $category = $item ? $item->category : '';

        $motorTestingMaster = MotorTestingMaster::where('plant_id', $plantId)->where('item_id', $item->id)->first();

        if (!$motorTestingMaster)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Item Code not found in motor testing master table for the plant : '$plant->name'!"
            ], 404);
        }

        $output = [
            "mot_subassembly_code"      => $motorTestingMaster->subassembly_code ?? "",
            "mot_model_name"        => $description,
            "mot_non_isi_model"     => $motorTestingMaster->isi_model ? "0" :"1",
            "mot_phase"             => $motorTestingMaster->phase ?? "",
            "mot_hp"                => $motorTestingMaster->hp ?? "",
            "mot_kw"                => $motorTestingMaster->kw ?? "",
            "mot_volt"              => $motorTestingMaster->volt ?? "",
            "mot_cur"               => $motorTestingMaster->current ?? "",
            "mot_rpm"               => $motorTestingMaster->rpm ?? "",
            "mot_rate_torque_kg"    => $motorTestingMaster->torque ?? "",
            "mot_freq"              => $motorTestingMaster->frequency ?? "",
            "mot_conn"              => $motorTestingMaster->connection ?? "",
            "mot_ins_res_limit"     => $motorTestingMaster->ins_res_limit ?? "",
            "mot_ins_res_type"      => $motorTestingMaster->ins_res_type ?? "",
            "mot_category"          => $category,
            "mot_routine_test_time" => $motorTestingMaster->routine_test_time ?? "",
            "mot_res_ry_ll"         => $motorTestingMaster->res_ry_ll ?? "",
            "mot_res_ry_ul"         => $motorTestingMaster->res_ry_ul ?? "",
            "mot_res_yb_ll"         => $motorTestingMaster->res_yb_ll ?? "",
            "mot_res_yb_ul"         => $motorTestingMaster->res_yb_ul ?? "",
            "mot_res_br_ll"         => $motorTestingMaster->res_br_ll ?? "",
            "mot_res_br_ul"         => $motorTestingMaster->res_br_ul ?? "",
            "mot_lock_volt_limit"   => $motorTestingMaster->lock_volt_limit ?? "",
            "mot_leak_cur_limit"    => $motorTestingMaster->leak_cur_limit ?? "",
            "mot_lock_cur_ll"       => $motorTestingMaster->lock_cur_ll ?? "",
            "mot_lock_cur_ul"       => $motorTestingMaster->lock_cur_ul ?? "",
            "mot_noload_cur_ll"     => $motorTestingMaster->noload_cur_ll ?? "",
            "mot_noload_cur_ul"     => $motorTestingMaster->noload_cur_ul ?? "",
            "mot_noload_pow_ll"     => $motorTestingMaster->noload_pow_ll ?? "",
            "mot_noload_pow_ul"     => $motorTestingMaster->noload_pow_ul ?? "",
            "mot_noload_spd_ll"     => $motorTestingMaster->noload_spd_ll ?? "",
            "mot_noload_spd_ul"     => $motorTestingMaster->noload_spd_ul ?? ""
        ];

        return response()->json($output, 200);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {
        //
    }
}
