<?php

namespace App\Http\Controllers;

use App\Models\Item;
use App\Models\Plant;
use App\Models\WeightValidation;
use Illuminate\Http\Request;
use Str;

class ObdController 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("ERROR: Unauthorized", 403)
        //         ->header('Content-Type', 'text/plain');
        // }
        if ("Bearer " . $expectedToken != $header_auth)
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Invalid authorization token!'
            ], 403);
        }

        try
        {
            $data = $request->all();
            // Validate required fields
            $missing = [];
            if (empty($data['plant_name'])) $missing[] = 'plant_name';
            if (empty($data['obd_number'])) $missing[] = 'obd_number';
            if (empty($data['line_numbers'])) $missing[] = 'line_numbers';

            if (!empty($missing))
            {
                $message = "Missing required field(s): " . implode(', ', $missing);
                // return response($message, 400)->header('Content-Type', 'text/plain');
                return response()->json([
                    'status_code' => 'ERROR',
                    'status_description' => $message,
                ], 400);
            }

            // OBD Number validation
            $obdNumber = $data['obd_number'];
            if (Str::length($obdNumber) < 8 || !ctype_alnum($obdNumber))
            {
                // return response("ERROR: OBD Number should contain minimum 8 digits", 400)
                //     ->header('Content-Type', 'text/plain');
                return response()->json([
                    'status_code' => 'ERROR',
                    'status_description' => "OBD number should contain minimum 8 digit alpha-numeric values only!"
                ], 400);
            }

            // Lookup plant_id by plant_name
            $plantId = Plant::where('name', $data['plant_name'])->value('id');
            if (!$plantId) {
                // return response("ERROR: Plant '{$data['plant_name']}' not found", 404)
                //     ->header('Content-Type', 'text/plain');
                return response()->json([
                    'status_code' => 'ERROR',
                    'status_description' => "Plant '{$data['plant_name']}' not found!"
                ], 404);
            }

            //Check if OBD number exists for that plant
            $obdRecords = WeightValidation::where('plant_id', $plantId)
                ->where('obd_number', $obdNumber)
                ->exists();

            if (!$obdRecords)
            {
                // return response( "ERROR: OBD Number '$obdNumber' not found for plant '{$data['plant_name']}'",404)->header('Content-Type', 'text/plain');
                return response()->json([
                    'status_code' => 'ERROR',
                    'status_description' => "OBD Number '$obdNumber' not found for plant '{$data['plant_name']}'!"
                ], 404);
            }

            $missingLines = [];
            $alreadyUpdatedLines = [];

            foreach ($data['line_numbers'] as $line)
            {
                if ($line['line_number'] == '' || $line['line_number'] == null)
                {
                    // return response("ERROR: Line Number can't be empty", 400)
                    //     ->header('Content-Type', 'text/plain');
                    return response()->json([
                        'status_code' => 'ERROR',
                        'status_description' => "Line Number can't be empty!"
                    ], 404);
                }

                $record = WeightValidation::where('plant_id', $plantId)
                    ->where('obd_number', $data['obd_number'])
                    ->where('line_number', $line['line_number'])
                    ->first();

                if (!$record)
                {
                    $missingLines[] = $line['line_number'];
                    continue;
                }

                $mandatoryFields = ['vehicle_number', 'bundle_number', 'heat_number', 'picked_weight', 'scanned_by'];
                $missingFields = [];

                foreach ($mandatoryFields as $field)
                {
                    if ($line[$field] == '' || $line[$field] == null)
                    {
                        $missingFields[] = ucwords(str_replace('_', ' ', $field));
                    }
                }

                if (!empty($missingFields))
                {
                    if (count($missingFields) == 1)
                    {
                        $fieldsString = $missingFields[0];
                    }
                    else
                    {
                        $lastField = array_pop($missingFields);
                        $fieldsString = implode(', ', $missingFields) . ' and ' . $lastField;
                    }

                    $message = $fieldsString . " can't be empty for line_number {$line['line_number']}!";
                    // return response($message, 400)->header('Content-Type', 'text/plain');
                    return response()->json([
                        'status_code' => 'ERROR',
                        'status_description' => $message
                    ], 400);
                }
            }

            if (!empty($missingLines)) {
                $message = "Line(s) " . implode(', ', $missingLines) . " not found for Plant '{$data['plant_name']}' and OBD Number: '{$data['obd_number']}'!";
                // return response($message, 404)->header('Content-Type', 'text/plain');
                return response()->json([
                    'status_code' => 'ERROR',
                    'status_description' => $message
                ], 404);
            }

            $seenPairs = [];
            $internalDuplicates = [];
            $bundleChecks = [];

            //Check for duplicates within the request
            foreach ($data['line_numbers'] as $line) {
                $lineNumber = $line['line_number'];
                $bundleNumber = trim((string)$line['bundle_number']);
                $pairKey = $lineNumber . '|' . $bundleNumber;

                if (isset($seenPairs[$pairKey])) {
                    $internalDuplicates[] = "Line Number {$lineNumber} with Bundle Number {$bundleNumber}";
                } else {
                    $seenPairs[$pairKey] = true;
                    $bundleChecks[] = [
                        'line_number' => $lineNumber,
                        'bundle_number' => $bundleNumber,
                    ];
                }
            }

            //Check for duplicates in the database

            $bundleNumbers = array_column($bundleChecks, 'bundle_number');
            $lineNumbers = array_column($bundleChecks, 'line_number');

            $existingBundles = WeightValidation::where('plant_id', $plantId)
                ->where('obd_number', $obdNumber)
                ->whereIn('line_number', $lineNumbers)
                ->whereIn('bundle_number', $bundleNumbers)
                ->get(['line_number', 'bundle_number']);

            $grouped = [];
            foreach ($existingBundles as $row) {
                $line = $row->line_number;
                $bundle = $row->bundle_number;

                if (!isset($grouped[$line])) {
                    $grouped[$line] = [];
                }
                if ($bundle && !in_array($bundle, $grouped[$line])) {
                    $grouped[$line][] = $bundle;
                }
            }

            $dbDuplicates = [];
            foreach ($grouped as $line => $bundles) {
                $bundlesStr = implode(', ', $bundles);
                $dbDuplicates[] = "Line {$line}, has bundle numbers : {$bundlesStr}";
            }

            //Return all errors if any duplicates found
            $allDuplicates = [];
            if (!empty($internalDuplicates))
            {
                $allDuplicates[] = "Duplicate(s) " . implode(', ', $internalDuplicates);
            }
            if (!empty($dbDuplicates))
            {
                $allDuplicates[] = "Already exists in database: " . implode('; ', $dbDuplicates);
            }

            if (!empty($allDuplicates)) {
                // return response(
                //     "Error:" . implode("\n", $allDuplicates),
                //     400
                // )->header('Content-Type', 'text/plain');

                $retRes = implode(", and ", $allDuplicates);
                return response()->json([
                    'status_code' => 'ERROR',
                    'status_description' => $retRes
                ], 400);
            }

            //..
            $updated = 0;
            $inserted = 0;
            $updatedLines = [];
            $insertedLines = [];
            $lineTracker = [];

            foreach ($data['line_numbers'] as $line)
            {
                $lineNumber = $line['line_number'];
                $existing = WeightValidation::where('plant_id', $plantId)
                ->where('obd_number', $obdNumber)
                ->where('line_number', $lineNumber)
                ->where(function ($query) {
                    $query->whereNull('bundle_number')
                          ->orWhere('bundle_number', '');
                })
                ->first();

                if($existing)
                {
                    $existing->update([
                        'vehicle_number'   =>  $line['vehicle_number'] ?? null,
                        'bundle_number' => $line['bundle_number'] ?? null,
                        'heat_number' => $line['heat_number'] ?? null,
                        'picked_weight' => $line['picked_weight'] ?? null,
                        'scanned_by'    => $line['scanned_by'] ?? null,
                        'updated_at'    => now(),
                    ]);
                    $updated++;
                    $updatedLines[] = $lineNumber;
                    $lineTracker[$lineNumber] = 1;
                }
                else
                {
                    $original = WeightValidation::where([
                        'plant_id'    => $plantId,
                        'obd_number'  => $obdNumber,
                        'line_number' => $lineNumber,
                    ])->orderBy('id')->first();

                    WeightValidation::create([
                        'plant_id'       => $plantId,
                        'obd_number'     => $obdNumber,
                        'line_number'    => $lineNumber,
                        'item_id'        => $original->item_id ?? null,
                        'vehicle_number' => $line['vehicle_number'] ?? null,
                        'bundle_number'  => $line['bundle_number'] ?? null,
                        'picked_weight'  => $line['picked_weight'] ?? null,
                        'scanned_by'     => $line['scanned_by'] ?? null,
                        'batch_number'   => $original->batch_number ?? null,
                        'heat_number'    => $line['heat_number'] ?? null,
                        'obd_weight'     => $original->obd_weight ?? null,
                        'created_at'     => now(),
                        'updated_at'     => now(),
                    ]);

                    $inserted++;
                    $insertedLines[] = $lineNumber;
                    $lineTracker[$lineNumber] = isset($lineTracker[$lineNumber]) ? $lineTracker[$lineNumber] + 1 : 1;
                }
            }

            $responseMessage = "OBD Number '{$obdNumber}'";

            if ($updated > 0) {
                $responseMessage .= " updated successfully. Line Numbers: {" . implode(', ', $updatedLines) . "}";
            }

            if ($inserted > 0) {
                $responseMessage .= "Inserted successfully. Line Numbers: {" . implode(', ', $insertedLines) . "}";
            }

            // return response($responseMessage, 200)
            //     ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'SUCCESS',
                'status_description' => $responseMessage,
            ], 200);

        }
        catch (\Exception $e)
        {
            // response("ERROR: Server error", 500)->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Store OBD data internal server error : '.$e?->getCode()
            ], 500);
        }
    }

    //Route::get('obd/get-test-datas', [ObdController::class, 'get_test']);
    public function get_test(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);
        }

        // $plantCode = $request->header('plant-code');
        // if (empty($plantCode))
        // {
        //     return response()->json([
        //         'status_code' => 'ERROR',
        //         'status_description' => "Plant code can't be empty"
        //     ], 400);
        // }
        // else if(Str::length($plantCode) < 4 || !is_numeric($plantCode))
        // {
        //     return response()->json([
        //         'status_code' => 'ERROR',
        //         'status_description' => "Plant code should contain minimum 4 digits numeric values only!"
        //     ], 400);
        // }

        // $plantId = Plant::where('code', $plantCode)->value('id');

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


        $productionOrder = $request->header('production-order');
        if (empty($productionOrder))
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Production order can't be empty!"
            ], 400);
        }
        else if(Str::length($productionOrder) < 7 || !is_numeric($productionOrder))
        {
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Production order should contain minimum 7 digits numeric values only!"
            ], 400);
        }

        $prodOrderExist = ($productionOrder == '1234567' || $productionOrder == '7654321');

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

        try
        {
            //return response("Successfully GET request Received", 200)->header('Content-Type', 'text/plain');
            $itemCode = Item::where('code', '123456')->where('plant_id', 1)->first();
            return response()->json([
                'item_code' => $itemCode->code,
                'item_description' => $itemCode->description
            ], 200);
        }
        catch (\Exception $e)
        {
            //return response("ERROR: GET test data server error", 500)->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => 'Get test data internal server error : '.$e?->getCode()
            ], 500);
        }
    }

    public function get_obd(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("ERROR: Unauthorized", 403)
        //         ->header('Content-Type', 'text/plain');
        // }

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

        $plantName = $request->header('plant-name');
        $obdNumber = $request->header('obd-number');

        if (empty($plantName))
        {
            // return response("ERROR: Plant Name can't be empty", 400)
            //     ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "Plant Name can't be empty!"
            ], 400);
        }
        else if(empty($obdNumber))
        {
            // return response("ERROR: OBD Number can't be empty", 400)
            // ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "OBD Number can't be empty!"
            ], 400);
        }
        else if(Str::length($obdNumber) < 8 || !ctype_alnum($obdNumber))
        {
            // return response("ERROR: OBD Number should contain minimum 8 digits: '$obdNumber'", 400)
            // ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "OBD number should contain minimum 8 digit alpha-numeric values only!"
            ], 400);
        }

        // Fetch the plant id by name
        $plantId = Plant::where('name', $plantName)->value('id');

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

        // $records = WeightValidation::where('plant_id', $plantId)
        //     ->where('obd_number', $obdNumber)
        //     ->get();
         // Fetch and filter records where vehicle_number is empty or null

         $exists = WeightValidation::where('plant_id', $plantId)
        ->where('obd_number', $obdNumber)
        ->exists();

        if (!$exists)
        {
            // return response("ERROR: OBD number $obdNumber does not exist for plant '$plantName'", 404)
            //     ->header('Content-Type', 'text/plain');
            return response()->json([
                'status_code' => 'ERROR',
                'status_description' => "OBD number $obdNumber does not exist for plant '$plantName'!"
            ], 400);
        }

        $records = WeightValidation::where('plant_id', $plantId)
        ->where('obd_number', $obdNumber)
        ->get()
        ->filter(function ($record) {
            return $record->vehicle_number == '' || $record->vehicle_number == null;
        });

        if ($records->isEmpty()) {
            // return response("SUCCESS: Already scanning process completed for the OBD Number", 200)->header('Content-Type', values: 'text/plain');
            return response()->json([
                'status_code' => 'SUCCESS',
                'status_description' => "Already weight validation completed for the OBD Number!"
            ], 200);
        }

        $itemIds = $records->pluck('item_id')->unique();
        $itemCodes = Item::whereIn('id', $itemIds)
            ->select('id', 'code', 'description')
            ->get()
            ->keyBy('id');

        $ObdResponseStructure = [
            'OBD_Number' => [
                [
                    'OBD_Number' => $obdNumber,
                    'Line_Numbers' => $records->map(function ($item) use ($itemCodes) {
                        $itemInfo = $itemCodes[$item->item_id] ?? null;
                        return [
                            'Line' => $item->line_number ?? "",
                            'Material_Code' => $itemInfo->code ?? "",
                            'Material_Description' => $itemInfo->description ?? "",
                            'Batch_Number' => $item->batch_number ?? "",
                            // 'Heat_Number' => $item->heat_number ?? "",
                            'Actual_Weight' => $item->obd_weight ?? "",
                        ];
                    })->values()->toArray()
                ]
            ]
        ];
        return response()->json($ObdResponseStructure);
    }

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

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