<?php

namespace App\Services;

use App\Models\UsageAttribute;
use App\Models\Product;
use App\Traits\HasResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class UsageAttributeService
{
    use HasResponse;

    public function list($params, $withPagination)
    {
        $attributes = UsageAttribute::where('status', 1)->orderBy('id', 'desc');

        $search = isset($params['search']) ? $params['search'] : '';
        if($search){
            $attributes->where(function ($query) use ($search) {
                $query->where('name', 'like', "%$search%")
                ->orWhere('code', 'like', "%$search%");
            });
        }

        $attributes = !empty($withPagination)
            ? $attributes->paginate($withPagination['perPage'], page: $withPagination['page'])
            : $attributes->get();

        return $this->successResponse('Lectura exitosa.', $attributes);
    }

    public function listByCompany($params, $withPagination)
    {
        $attributes = UsageAttribute::where('status', 1)->orderBy('id', 'desc');

        $idcompany = isset($params['idcompany']) ? $params['idcompany'] : '';
        if($idcompany) {
            $attributes->where(function ($query) use ($idcompany) {
                $query->where('idcompany', $idcompany);
            });
        }

        $search = isset($params['search']) ? $params['search'] : '';
        if($search){
            $attributes->where(function ($query) use ($search) {
                $query->where('name', 'like', "%$search%")
                ->orWhere('code', 'like', "%$search%");
            });
        }

        $attributes = !empty($withPagination)
            ? $attributes->paginate($withPagination['perPage'], page: $withPagination['page'])
            : $attributes->get();

        return $this->successResponse('Lectura exitosa.', $attributes);
    }

    public function register($params)
    {
        DB::beginTransaction();
        try {
            
            $nameExisting = UsageAttribute::where('name', $params['name'])->where('idcompany', $params['idcompany'])->where('status', 1)->first();
            if ($nameExisting) return $this->errorResponse('El nombre ya se encuentra registrado.', 400);

            $codeExisting = UsageAttribute::where('code', $params['code'])->where('idcompany', $params['idcompany'])->where('status', 1)->first();
            if ($codeExisting) return $this->errorResponse('El código ya se encuentra registrado.', 400);

            $usersession = Auth::user();

            $attribute = UsageAttribute::create([
                'code' => $params['code'],
                'name' => $params['name'],
                'description' => $params['description'],
                'idspecificuses' => $params['idspecificuses'],
                'createdby' => $usersession->id,
                'idcompany' => $params['idcompany'],
            ]);
            $attribute->save();

            DB::commit();
            return $this->successResponse('Uso de atributo creado satisfactoriamente.', $attribute);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la creación de un uso de atributo.', $th->getMessage());
        }
    }

    public function relationProducts($id, $params)
{
    DB::beginTransaction();
    try {
        # Verificar validez del atributo
        $validate = $this->verifyAttribute($id);
        if (!$validate->original['status']) return $validate;

        # Validar el array de productos enviados
        if (isset($params['products'])) {
            $a_idproducts = [];
            $productIds = array_column($params['products'], 'id'); # Obtener los IDs de los productos enviados

            # Obtener todos los productos que tienen la relación con el ID actual
            $productsWithRelation = Product::whereJsonContains('iduses', $id)->get();

            foreach ($productsWithRelation as $productWithRelation) {
                if (!in_array($productWithRelation->id, $productIds)) {
                    # Si el producto no está en la lista de productos enviados, quitar la relación
                    $iduses = is_string($productWithRelation->iduses) ? json_decode($productWithRelation->iduses, true) : $productWithRelation->iduses;

                    if (($key = array_search($id, $iduses)) !== false) {
                        unset($iduses[$key]); # Quitar el ID del array
                    }

                    # Actualizar el campo iduses y guardar el producto
                    $productWithRelation->iduses = array_values($iduses); # Reindexar el array y asegurarse de que sean números
                    $productWithRelation->save();
                }
            }

            foreach ($params['products'] as $key => $product) {
                # Validar si ya existe la relación en el producto
                $exists = Product::where('id', $product['id'])->whereJsonContains('iduses', $id)->exists();
                if ($exists) {
                    $a_idproducts[] = $product['id'];
                } else {
                    # Obtener el producto y actualizar el array iduses
                    $productModel = Product::find($product['id']);
                    $iduses = is_string($productModel->iduses) ? json_decode($productModel->iduses, true) : $productModel->iduses;

                    # Asegurarse de que iduses es un array
                    if (!is_array($iduses)) {
                        $iduses = [];
                    }

                    # Agregar el nuevo id al array
                    $iduses[] = (int)$id;

                    # Actualizar el campo iduses y guardar el producto
                    $productModel->iduses = array_values($iduses); # Reindexar el array y asegurarse de que sean números
                    $productModel->save();
                }
            }
        }

        DB::commit();
        return $this->successResponse('Uso de atributo actualizado satisfactoriamente.');
    } catch (\Throwable $th) {
        DB::rollBack();
        return $this->externalError('durante la actualización productos relacionados de un uso de atributo.', $th->getMessage());
    }
}


    public function update($id, $params)
    {
        DB::beginTransaction();
        try {
            # Verificar validez del atributo
            $validate = $this->verifyAttribute($id);
            if (!$validate->original['status']) return $validate;

            $nameExisting = UsageAttribute::where('name', $params['name'])->where('id','!=', $id)->where('idcompany', $params['idcompany'])->where('status', 1)->first();
            if ($nameExisting) return $this->errorResponse('El nombre ya se encuentra registrado.', 400);

            $codeExisting = UsageAttribute::where('code', $params['code'])->where('id','!=', $id)->where('idcompany', $params['idcompany'])->where('status', 1)->first();
            if ($codeExisting) return $this->errorResponse('El código ya se encuentra registrado.', 400);

            $attribute = UsageAttribute::find($id);
            $attribute->code = $params['code'];
            $attribute->name = $params['name'];
            $attribute->description = $params['description'];
            $attribute->idspecificuses = $params['idspecificuses'];
            $attribute->save();

            DB::commit();
            return $this->successResponse('Uso de atributo actualizado satisfactoriamente.', $attribute);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la actualización de un uso de atributo.', $th->getMessage());
        }
    }

    public function delete($id)
    {
        DB::beginTransaction();
        try {
            # Verificar validez de l atributo
            $validate = $this->verifyAttribute($id);
            if (!$validate->original['status']) return $validate;

            $attribute = UsageAttribute::find($id);
            $attribute->status = 2;
            $attribute->save();

            DB::commit();
            return $this->successResponse('Uso de atributo eliminado satisfactoriamente.', $attribute);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la eliminación de un uso de atributo.', $th->getMessage());
        }
    }

    private function verifyAttribute($idattribute)
    {
        $attribute = UsageAttribute::where('id', $idattribute)->where('status', 1)->first();
        if (!$attribute) return $this->errorResponse('No se encontró el uso de atributo.', 400);

        return $this->successResponse('OK');
    }
}
