<?php

namespace App\Modules\Bookings;

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\BaseController;

class DevicesControllerRESTv1 extends BaseController
{
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        $query = Device::select('devices.*')->with('model_number', 'model_number.manufacturer');

        if (request()->get('client_type') && request()->get('client_id')) {
            $query->where('client_id', '=', request()->get('client_id'))->where('client_type', '=', request()->get('client_type'));
        }

        if (request()->get('task_id')) {
            $query->whereHas('repairs', function ($q) {
                $q->where('tasks.id', '=', request()->get('task_id'));
            });
        }

        if (request()->get('query')) {
            $query->join('model_numbers', 'devices.model_number_id', '=', 'model_numbers.id');
            $query->join('manufacturers', 'manufacturers.id', '=', 'model_numbers.manufacturer_id');
            // $query->where(DB::raw("CONCAT_WS(' ', manufacturers.name, model_numbers.model_number)"), 'like', '%'. request()->get('query') .'%');

            $query->where(function ($q) {
                $tokens = explode(' ', request()->get('query'));

                foreach ($tokens as $token) {
                    $q->orWhere('manufacturers.name', 'like', '%'.$token.'%');
                    $q->orWhere('model_numbers.model_number', 'like', '%'.$token.'%');
                }
            });
        }

        // Apply limits and execute the query
        $query = $query->paginate(request()->get('limit', 20));

        $response = [
            'success'      => true,
            'data'         => $query->getCollection()->toArray(),
            'total'        => $query->total(),
            'current_page' => $query->currentPage(),
            'last_page'    => $query->lastPage(),
            'per_page'     => $query->perPage(),
            'from'         => $query->firstItem(),
            'to'           => $query->lastItem(),
        ];

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

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store()
    {
        $data = request()->all();

        // Validate the input data including serial number uniqueness
        $validator = \Validator::make($data, [
            'client_id'          => 'required',
            'client_type'        => 'required',
            'type'               => 'required',
            'serial_number'      => 'nullable|unique:devices,serial_number',
        ]);

        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()->all()], 400);
        }

        // If the model_number or manufacturer does not exist, creates those
        if (! isset($data['model_number']['id'])) {
            if (! isset($data['model_number']['manufacturer_id'])) {
                $manufacturer = Manufacturer::create($data['model_number']['manufacturer']);

                if (! $manufacturer->id) {
                    return response()->json(['errors' => $manufacturer->errors->all()], 400);
                }

                $data['model_number']['manufacturer_id'] = $manufacturer->id;
            }

            $model_number = ModelNumber::create($data['model_number']);

            if (! $model_number->id) {
                return response()->json(['errors' => $model_number->errors->all()], 400);
            }

            $data['model_number_id'] = $model_number->id;
        } else {
            $data['model_number_id'] = $data['model_number']['id'];
        }

        try {
            $device = Device::create($data);

            if (! $device->id) {
                return response()->json(['errors' => ['Failed to create device']], 400);
            }

            $device->load('model_number.manufacturer');

            return $device;
        } catch (\Illuminate\Database\QueryException $e) {
            // Handle database constraint violations
            if ($e->errorInfo[1] == 1062) { // Duplicate entry error code
                return response()->json(['errors' => ['The serial number has already been taken.']], 400);
            }
            
            // Handle other database errors
            return response()->json(['errors' => ['Database error occurred while creating device.']], 500);
        } catch (\Exception $e) {
            // Handle any other errors
            return response()->json(['errors' => ['An error occurred while creating the device.']], 500);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function show($id)
    {
        $device = Device::find($id);

        $device->load('model_number', 'model_number.manufacturer');

        if (! $device) {
            return response()->json(['error' => 'Device not found.'], 404);
        }

        return response()->json($device->toArray());
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function update($id)
    {
        $device = Device::find($id);

        if (!$device) {
            return response()->json(['error' => 'Device not found.'], 404);
        }

        $data = request()->except('id');

        // Validate the input data including serial number uniqueness (excluding current device)
        if (isset($data['serial_number'])) {
            $validator = \Validator::make($data, [
                'serial_number' => 'nullable|unique:devices,serial_number,' . $id,
            ]);

            if ($validator->fails()) {
                return response()->json(['errors' => $validator->errors()->all()], 400);
            }
        }

        if (! empty($data['model_number']) && ! $data['model_number']['id']) {
            if (! $data['model_number']['manufacturer_id']) {
                $manufacturer = Manufacturer::create($data['model_number']['manufacturer']);

                if (! $manufacturer->id) {
                    return response()->json(['errors' => $manufacturer->errors->all()], 400);
                }

                $data['model_number']['manufacturer_id'] = $manufacturer->id;
            }

            $model_number = ModelNumber::create($data['model_number']);

            if (! $model_number->id) {
                return response()->json(['errors' => $model_number->errors->all()], 400);
            }

            $data['model_number_id'] = $model_number->id;
        }

        try {
            $device->fill($data);

            if ($device->save()) {
                $device->load('model_number', 'model_number.manufacturer');

                return response()->json($device->toArray());
            } else {
                return response()->json([
                    'errors' => ['Failed to update device'],
                ], 400);
            }
        } catch (\Illuminate\Database\QueryException $e) {
            // Handle database constraint violations
            if ($e->errorInfo[1] == 1062) { // Duplicate entry error code
                return response()->json(['errors' => ['The serial number has already been taken.']], 400);
            }
            
            // Handle other database errors
            return response()->json(['errors' => ['Database error occurred while updating device.']], 500);
        } catch (\Exception $e) {
            // Handle any other errors
            return response()->json(['errors' => ['An error occurred while updating the device.']], 500);
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function destroy($id)
    {
        $device = Device::find($id);

        // Access validations
        // should be implemented here...

        if (! $device) {
            return response()->json(['error' => 'Device not found.'], 404);
        }

        if ($device->delete()) {
            return response()->json($device->toArray());
        } else {
            return response()->json([
                'errors' => $device->errors->all(),
            ], 400);
        }
    }

    /**
     * Creates the model number and model if it doesn't exist.
     *
     * @return Integer - the model number id.
     */
    protected function _getModelNumber()
    {
        if (! request()->get('model_number')) {
            return response()->json(['success' => false, 'errors' => ['Model number is required.']], 400);
        }

        if (! request()->get('manufacturer')) {
            return response()->json(['success' => false, 'errors' => ['Manufacturer is required.']], 400);
        }

        $manufacturer = Manufacturer::where('name', '=', request()->get('manufacturer'))->first();

        if (! $manufacturer) {
            $manufacturer = Manufacturer::create(['name' => request()->get('manufacturer')]);
        }

        $model_number = ModelNumber::where('model_number', '=', request()->get('model_number'))
            ->where('manufacturer_id', '=', $manufacturer->id)
            ->first();

        if (! $model_number) {
            $model_number = ModelNumber::create([
                'model_number'   => request()->get('model_number'),
                'manufacturer_id' => $manufacturer->id,
            ]);
        }

        return $model_number->id;
    }
}
