<?php

namespace App\Services;

use App\Http\Resources\PriceListProductResource;
use App\Http\Resources\ProductResource;
use App\Http\Resources\ProductWithoutListResource;
use App\Models\DetailPriceListProduct;
use App\Models\DetailUserCompany;
use App\Models\PriceList;
use App\Models\Product;
use App\Models\Salesman;
use App\Models\SalesmanBranchOffice;
use App\Models\Supplier;
use App\Traits\HasResponse;
use Illuminate\Support\Facades\DB;
use stdClass;
use Tymon\JWTAuth\Facades\JWTAuth;

class PriceListProductsService
{
    use HasResponse;

    // public $iddetailUser;
    // public $userCompany;

    // public function __construct()
    // {
    //     $this->iddetailUser = JWTAuth::payload()->get('iddetail_user');
    //     $this->userCompany = DetailUserCompany::find($this->iddetailUser);
    // }

    public function list($withPagination)
    {
        $details = DetailPriceListProduct::priceListProductsFilters(); # Filtrado por el modelo

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

        $details = PriceListProductResource::collection($details->load('pricelist', 'product', 'company'));

        # Alternativa cuando no encuentra la lista de producto
        if ($details->isEmpty()) {
            $products = Product::where('id', request('idproduct'))->productFilters()
                ->orderBy('tbl_products.id', 'desc');

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

            $products = ProductWithoutListResource::collection($products->load(
                'stock',
                'company',
                'cointType',
                'category',
                'subcategory',
                'specificsubcategory',
                'type',
                'supplier',
                'unitmeasure',
                'businessarea',
                'classification'
            ));

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

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

    public function register($params)
    {
        DB::beginTransaction();
        try {
            # Verificar duplicidad de sucursal
            $branchOfficeExisting = SalesmanBranchOffice::branchOfficeID($params['idsalesman'], $params['idbranchoffice'])->active()->first();
            if ($branchOfficeExisting) return $this->errorResponse('El vendedor ya se encuentra registrado a esta sucursal.', 400);

            $salesman = SalesmanBranchOffice::create([
                'idsalesman'        => $params['idsalesman'],
                'idbranchoffice'    => $params['idbranchoffice'],
                'idcompany'         => $params['idcompany']
            ]);
            $salesman->fresh();

            DB::commit();
            return $this->successResponse('Vendedor agregado a una sucursal satisfactoriamente.', $salesman);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la asignacion de un vendedor a una sucursal.', $th->getMessage());
        }
    }

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

            $salesman = SalesmanBranchOffice::find($id);
            $salesman->update($params);

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

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

            $salesman = SalesmanBranchOffice::find($id);
            $salesman->update(['status' => 2]);

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

    private function verifySalesmanBranchOffice($id, $branchoffice = null)
    {
        $salesman = SalesmanBranchOffice::activeForID($id)->first();
        if (!$salesman) return $this->errorResponse('El vendedor seleccionado no esta disponible en esta sucursal', 400);

        if (isset($branchoffice)) {
            $validateBranchOffice = SalesmanBranchOffice::branchOfficeID($salesman->idsalesman, $branchoffice, $id)->active()->first();
            if ($validateBranchOffice) return $this->errorResponse('La sucursal ya se encuentra registrado.', 400);
        }

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

    public function listProductNew($params, $withPagination, $group = true)
    {
        try {
            $products = Product::productFilters()
                ->orderBy('id', 'desc');

            if (isset($params['search'])) {
                $search = $params['search'];

                // Hacer un leftJoin con la tabla de categorías
                $products = $products
                    ->leftJoin('tbl_categories', 'tbl_products.idcategory', '=', 'tbl_categories.id')
                    ->where(function ($query) use ($search) {
                        $query->where('tbl_products.code_system', 'LIKE', '%' . $search . '%')
                            ->orWhere('tbl_products.code_erp', 'LIKE', '%' . $search . '%')
                            ->orWhere('tbl_products.barcode', 'LIKE', '%' . $search . '%')
                            ->orWhere('tbl_products.name', 'LIKE', '%' . $search . '%')  // Especifica tabla de productos
                            ->orWhere('tbl_categories.name', 'LIKE', '%' . $search . '%');  // Especifica tabla de categorías
                    });

                // Asegúrate de que el `orderBy` se refiera a la tabla correcta
                $products = $products->orderBy('tbl_products.id', 'desc');
            }


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

            $products = ProductWithoutListResource::collection($products->load(
                'stock',
                'company',
                'cointType',
                'category',
                'subcategory',
                'specificsubcategory',
                'type',
                'supplier',
                'unitmeasure',
                'businessarea',
                'classification'
            ));

            return $this->successResponse('Lectura exitosa sin lista de precios.', $products);
        } catch (\Throwable $th) {
            // throw $th;
            return $this->externalError('durante la visualización de productos.', $th->getMessage());
        }
    }

    public function listProduct($params, $withPagination, $group = true)
    {
        try {
            $user = JWTAuth::user();
            $iddetailUser = JWTAuth::payload()->get('iddetail_user');
            $userCompany = DetailUserCompany::find($iddetailUser);

            if ($userCompany->iduser_type == 3) {
                $salesman = Salesman::rut($user->rut)->active()->first();
                $params['idsalesman'] = $salesman->id;
            }

            $products = [];

            // 1=general, 2=sucursal, 3=salesman, 4=segment, 5=customer
            if (isset($params['idcustomer'])) {
                $customer = Supplier::activeForID($params['idcustomer'])->first();

                $products = $this->getValidateProducts(5, 'priceListCustomer', 'id', $withPagination, $params, $customer);

                if (count($products) == 0) $products = $this->getValidateProducts(4, 'priceListSegment', 'idsegment', $withPagination, $params, $customer);
            }

            if (isset($params['idsalesman']) && count($products) == 0) {
                $data = new stdClass();
                $data->idsalesman = $params['idsalesman'];

                $products = $this->getValidateProducts(3, 'priceListSalesman', 'idsalesman', $withPagination, $params, $data);

                if (count($products) == 0) $products = $this->getValidateProducts(2, 'priceListBranchOffice', 'idbranchoffice', $withPagination, $params, $data);
            }

            if (count($products) == 0) $products = $this->getProductGeneral($withPagination, $params);

            // if(!isset($params['idcategory_product']) && $group) {
            //     $products = $this->groupCategory($products);
            // }

            # Alternativa cuando no encuentra la lista de producto
            if ($products->isEmpty()) {

                $products = Product::productFilters()
                    ->orderBy('tbl_products.id', 'desc');
                if (isset($params['code'])) {
                    $products = $products->where('code_erp', $params['code']);
                }
                if (isset($params['iduse'])) {
                    $useId = (int)$params['iduse'];
                    $products = $products->whereJsonContains('iduses', $useId);
                }
                if (isset($params['idspecific_use'])) {
                    $specificuseId = (int)$params['idspecific_use'];
                    $products = $products->whereJsonContains('idspecificuses', $specificuseId);
                }
                if (isset($params['search'])) {
                    $search = $params['search'];

                    $products = $products
                        ->leftJoin('tbl_categories', 'tbl_products.idcategory', '=', 'tbl_categories.id')
                        ->where(function ($query) use ($search) {
                            $query->where('tbl_categories.name', 'LIKE', '%' . $search . '%');
                        })
                        ->leftJoin('tbl_sub_categories', 'tbl_products.idsubcategory', '=', 'tbl_sub_categories.id')
                        ->where(function ($query) use ($search) {
                            $query->where('tbl_sub_categories.name', 'LIKE', '%' . $search . '%');
                        })
                        ->leftJoin('tbl_specific_sub_categories', 'tbl_products.idspecificsubcategory', '=', 'tbl_specific_sub_categories.id')
                        ->where(function ($query) use ($search) {
                            $query->where('tbl_specific_sub_categories.name', 'LIKE', '%' . $search . '%');
                        });
                }


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

                $products = ProductWithoutListResource::collection($products->load(
                    'stock',
                    'company',
                    'cointType',
                    'category',
                    'subcategory',
                    'specificsubcategory',
                    'type',
                    'supplier',
                    'unitmeasure',
                    'businessarea',
                    'classification'
                ));

                return $this->successResponse('Lectura exitosa sin lista de precios.', $products);
            }
            return $this->successResponse('OK', $products);
        } catch (\Throwable $th) {
            // throw $th;
            return $this->externalError('durante la visualización de productos.', $th->getMessage());
        }
    }

    public function searchProductNew($params, $withPagination)
    {
        # Inicializa las variables de resultados de productos
        $sellingProducts = [];
        $mostSearchedProducts = [];

        # Productos más vendidos
        if (request('sellingProducts')) {
            $sellingProductsQuery = DB::table('tbl_products')
                ->join('tbl_detail_ticket', 'tbl_products.id', '=', 'tbl_detail_ticket.idproduct')
                ->join('tbl_ticket', 'tbl_detail_ticket.idticket', '=', 'tbl_ticket.id')
                ->where('tbl_ticket.status', '=', 1)
                ->where('tbl_ticket.idcompany', '=', request('idcompany'))
                ->select('tbl_products.id as product_id', 'tbl_products.name', DB::raw('SUM(tbl_detail_ticket.amount) as total_sales'))
                ->groupBy('tbl_products.id')
                ->orderByDesc('total_sales')
                ->limit(10);

            $sellingProducts = $sellingProductsQuery->get();
        }

        # Productos más buscados
        if (request('mostSearchedProducts')) {
            $mostSearchedProductsQuery = DB::table('tbl_products')
                ->join('tbl_detail_shopping_cart', 'tbl_products.id', '=', 'tbl_detail_shopping_cart.idproduct')
                ->join('tbl_shopping_cart', 'tbl_detail_shopping_cart.idshopping_cart', '=', 'tbl_shopping_cart.id')
                ->where('tbl_shopping_cart.status', '=', 1)
                ->where('tbl_shopping_cart.idcompany', '=', request('idcompany'))
                ->select('tbl_products.id as product_id', 'tbl_products.name', DB::raw('SUM(tbl_detail_shopping_cart.quantity) as total_searchs'))
                ->groupBy('tbl_products.id')
                ->orderByDesc('total_searchs')
                ->limit(10);

            $mostSearchedProducts = $mostSearchedProductsQuery->get();
        }

        # Combina los resultados y elimina duplicados solo si ambos parámetros están presentes
        $mergedResults = collect();
        if (request('sellingProducts') && request('mostSearchedProducts')) {
            $mergedResults = $sellingProducts->merge($mostSearchedProducts)->unique('product_id');
        } elseif (request('sellingProducts')) {
            $mergedResults = $sellingProducts;
        } elseif (request('mostSearchedProducts')) {
            $mergedResults = $mostSearchedProducts;
        }

        # Extrae los IDs de productos únicos
        $productIds = $mergedResults->pluck('product_id')->toArray();

        # Si hay IDs de productos, los filtra con whereIn
        $dataQuery = Product::query();
        if (!empty($productIds)) {
            $dataQuery->whereIn('id', $productIds);
        } else {
            # Si no hay filtros, se aplica el filtro predeterminado
            $dataQuery->productFilters();
        }

        # Ejecutar paginación o obtener todos los productos
        if (!empty($withPagination)) {
            $data = $dataQuery->paginate($withPagination['perPage'], page: $withPagination['page']);
            $paginationTotal = $data->total();
        } else {
            $data = $dataQuery->get();
            $paginationTotal = $data->count();
        }

	$productPrices = collect();
        if (!empty($params['idcustomer'])) {
            $priceList = PriceList::where('type', 5)
                ->whereHas('priceListCustomer', function ($query) use ($params) {
                    $query->where('idcustomer', $params['idcustomer']);
                })
                ->where('idcompany', request('idcompany'))
                ->active()
                ->first();
    
            if ($priceList) {
                $productPrices = DetailPriceListProduct::where('idpricelist', $priceList->id)
                    ->where('idcompany', request('idcompany'))
                    ->active()
                    ->pluck('price', 'idproduct');
            }
        }
       

        # Cargar las relaciones necesarias
        $data = ProductWithoutListResource::collection($data->load(
            'company',
            'category',
            'subcategory',
            'specificsubcategory',
            'relationProductAttributes',
            'relationProductAttributes.childAttribute',
            'relationProductAttributes.parentAttribute'
        ))->transform(function ($product) use ($productPrices) {
            if ($productPrices->has($product['id'])) {
                $product['price_product'] = $productPrices[$product['id']];
            }
            return $product;
        });

        return $this->successPaginationResponse('Lectura exitosa.', $paginationTotal, $data);
    }

    public function searchProduct($params)
    {
        try {
            $products = $this->listProduct($params, [], false);
            if (!$products->original['status']) return $products;

            $message = $products->original['data']['message'];

            $products = $products->original['data']['detail'];

            $products = collect(json_decode(json_encode($products), true));

            // Inicializar arrays para almacenar la estructura final
            $result = ['category_product' => [], 'products' => []];

            // Procesar cada elemento de la colección
            $products->each(function ($item) use (&$result) {
                $categoryId = $item['idcategory_product'];
                $subcategory = $item['subcategory_product'];

                // Verificar si la categoría ya existe en el resultado
                $categoryIndex = array_search($categoryId, array_column($result['category_product'], 'id'));

                if ($categoryIndex === false) {
                    // Si no existe, agregar la categoría al resultado
                    $result['category_product'][] = [
                        'id' => $categoryId,
                        'name' => $item['category_product'],
                        'subcategory_product' => [],
                    ];

                    // Obtener el índice de la categoría recién agregada
                    $categoryIndex = count($result['category_product']) - 1;
                }

                // Verificar si la subcategoría ya existe en la categoría
                $subcategoryIndex = array_search($subcategory, array_column($result['category_product'][$categoryIndex]['subcategory_product'], 'name'));

                if ($subcategoryIndex === false && $subcategory) {
                    // Si no existe, agregar la subcategoría a la categoría
                    $result['category_product'][$categoryIndex]['subcategory_product'][] = [
                        'id' => $item['idsubcategory_product'],
                        'name' => $subcategory,
                    ];
                }

                // Agregar el producto al array de productos
                $result['products'][] = $item;
            });
            # Alternativa cuando no encuentra la lista de producto
            if (count($result['products']) < 1 || $message == 'Lectura exitosa sin lista de precios.') {

                $products = Product::productFilters()
                    ->orderBy('tbl_products.id', 'desc');

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

                $products = ProductWithoutListResource::collection($products->load(
                    'stock',
                    'company',
                    'cointType',
                    'category',
                    'subcategory',
                    'specificsubcategory',
                    'type',
                    'supplier',
                    'unitmeasure',
                    'businessarea',
                    'classification'
                ));

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

            return $this->successResponse('OK', $this->filterProducts($result['products'], [], $params, 1));
        } catch (\Throwable $th) {
            // throw $th;
            return $this->externalError('durante la busqueda de productos.', $th->getMessage());
        }
    }

    private function getProductGeneral($withPagination, $params)
    {
        $priceList = PriceList::where('type', 1)->active()->company()->pluck('id');

        $products = DetailPriceListProduct::whereIn('idpricelist', $priceList)->active()->company();

        return $this->filterProducts($products, $withPagination, $params);
    }

    private function getValidateProducts($type, $load, $field, $withPagination, $params, $data)
    {
        $searchField = $field != 'idbranchoffice' ? $data->$field : '';
        $column = ($field == 'id') ? 'idcustomer' : $field;

        $priceList = PriceList::where('type', $type)->company();

        if ($field == 'idbranchoffice') {
            $salesmanBranchOffice = SalesmanBranchOffice::where('idsalesman', $searchField)->active()->company();

            if (isset($params['idbranchoffice'])) {
                $salesmanBranchOffice = $salesmanBranchOffice->where('idbranchoffice', $params['idbranchoffice']);
            }

            $salesmanBranchOffice = $salesmanBranchOffice->pluck('idbranchoffice'); // cambiar luego

            $priceList = $priceList->whereHas($load, fn($q) => $q->whereIn($column, $salesmanBranchOffice))->active()->pluck('id');
        } else {
            $priceList = $priceList->whereHas($load, fn($q) => $q->where($column, $searchField))->active()->pluck('id');
        }

        $products = DetailPriceListProduct::whereIn('idpricelist', $priceList)->active()->company();

        return $this->filterProducts($products, $withPagination, $params);
    }

    private function filterProducts($products, $withPagination, $params, $validate = 0)
    {

        if (isset($params['search'])) {
            $products = $products->whereHas('product', fn($q) => $q->where('name', 'LIKE', '%' . $params['search'] . '%'));
        }

        if (isset($params['code'])) {
            $products = $products->whereHas('product', fn($q) => $q->where('code_system', 'LIKE', '%' . $params['code'] . '%'));
        }

        if (isset($params['idcategory_product'])) {
            $products = $products->whereHas('product', fn($q) => $q->where('idcategory', $params['idcategory_product']));
        }

        if (isset($params['idcategory'])) {
            $products = $products->whereHas('product', fn($q) => $q->where('idcategory', $params['idcategory']));
        }

        if (isset($params['idsubcategory_product'])) {
            $products = $products->whereHas('product', fn($q) => $q->where('idsubcategory', $params['idsubcategory_product']));
        }

        if (isset($params['idsubcategory'])) {
            $products = $products->whereHas('product', fn($q) => $q->where('idsubcategory', $params['idsubcategory']));
        }

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

        return PriceListProductResource::collection($products->load('pricelist', 'product', 'company'));
    }

    private function groupCategory($products)
    {
        $products = json_decode(json_encode($products));
        $products = collect($products);

        $groupedData = collect($products)->groupBy('idcategory_product');

        // Crear la estructura deseada
        return $groupedData->map(function ($group, $categoryId) {
            return [
                'id' => $categoryId,
                'name' => $group->first()->category_product,
                'products' => $group->toArray(),
            ];
        })->values()->all();
    }
}
