<?php

namespace App\Services;

use App\Http\Resources\PricelistResource;
use App\Http\Resources\ProductResource;
use App\Models\BranchOffice;
use App\Models\DetailPriceListBranchOffice;
use App\Models\DetailPriceListCustomer;
use App\Models\DetailPriceListProduct;
use App\Models\DetailPriceListSalesman;
use App\Models\DetailPriceListSegment;
use App\Models\PriceList;
use App\Models\Product;
use App\Models\Salesman;
use App\Models\Segment;
use App\Models\StockProduct;
use App\Models\Supplier;
use App\Traits\HasResponse;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;
use App\Imports\PriceListDataImport;

class PriceListService
{
    use HasResponse;

    public function list($withPagination)
    {
        $pricelists = PriceList::pricelistFilters() # Filtrado por el modelo
            ->orderBy('id', 'desc');

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

        $pricelists = PricelistResource::collection($pricelists->load('company', 'createdby'));

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

    public function register($params)
    {
        DB::beginTransaction();
        try {
            $codeExisting = PriceList::code($params['code'])->active()->first();
            if($codeExisting) return $this->errorResponse('El código ya se encuentra registrado.', 400);

            $nameExisting = PriceList::code($params['name'])->active()->first();
            if($nameExisting) return $this->errorResponse('El nombre ya se encuentra registrado.', 400);

            if ($params['type'] == '2' && sizeof($params['idbranchoffices']) == 0) return $this->errorResponse('La sucursal es obligatoria.', 400);
            if ($params['type'] == '3' && sizeof($params['idsalesman']) == 0) return $this->errorResponse('El vendedor es obligatorio.', 400);
            if ($params['type'] == '4' && sizeof($params['idsegments']) == 0) return $this->errorResponse('El segmento es obligatorio.', 400);
            if ($params['type'] == '5' && sizeof($params['idcustomers']) == 0) return $this->errorResponse('El cliente es obligatorio.', 400);

            // $arrayBranchOffices = json_decode($params['idbranchoffices'], true) ?? [];
            // $arraySalesman = json_decode($params['idsalesman'], true) ?? [];
            // $arraySegments = json_decode($params['idsegments'], true) ?? [];
            // $arraycustomers = json_decode($params['idcustomers'], true) ?? [];
            $arrayBranchOffices = $params['idbranchoffices'] ?? [];
            $arraySalesman = $params['idsalesman'] ?? [];
            $arraySegments = $params['idsegments'] ?? [];
            $arraycustomers = $params['idcustomers'] ?? [];

            $currentDate = Carbon::now()->format('Y-m-d');
            $iduser = Auth::user()->id;

            // $products = json_decode($params['products'], true);
            if ($params['type'] === '1') {
                $products = Product::active()->company()->get();
                $quantity_products = count($products);

            } else {
                $products = $params['products'] ?? [];
                $quantity_products = $params['quantity_products'] ?? count($products);
            }

            $priceList = PriceList::create([
                'code' => $params['code'],
                'name' => $params['name'],
                'description' => isset($params['description']) ? $params['description'] : null,
                'creation_date' => $currentDate,
                'validity_date' => $params['validity_date'] ?? null,
                'document_state' => $params['document_state'],
                'quantity_products' => $quantity_products,
                'type' => $params['type'],
                'discounttype' => $params['discounttype'],
                'max_desc_item' => $params['max_desc_item'] ?? 0,
                'max_desc_global' => $params['max_desc_global'] ?? 0,
                'created_by' => $iduser,
                'total' => $params['total'],
                'status' => $params['status'],
                'idcompany' => $params['idcompany'],
            ]);
            $priceList->fresh();


            $now = Carbon::now();

            $detail = [];
            if(sizeof($products) > 0 ){
                foreach ($products as $product) {
                    if (isset($product['id'])) $productModel = Product::where('id', $product['id'])->where('status', 1)->first();

                    $id = $product['id'] ?? $productModel->id ?? $product->id;
                    $price = $product['price'] ?? $productModel->price ?? $product->price ?? 0;
                    $cost = $product['cost'] ?? $productModel->cost ?? 0;
                    $discount = $product['discount'] ?? 0;
                    $stock = $product['stock'] ?? StockProduct::where('idproduct', $id)->active()->company()->sum('stock_system');

                    $detail[] = [
                        'price' => $price,
                        'cost' => $cost,
                        'stock' => $stock,
                        'subtotal' => $price * (int)$stock,
                        'discount' => $discount ?? 0,
                        'idpricelist' => $priceList->id,
                        'idproduct' => $id,
                        'idcompany' => $params['idcompany'],
                        'created_at' => $now,
                        'updated_at' => $now
                    ];

                    // $detail = DetailPriceListProduct::create([
                    //     'price' => $price,
                    //     'cost' => $cost,
                    //     'stock' => $stock,
                    //     'subtotal' => $price * $stock,
                    //     'discount' => $discount ?? 0,
                    //     'idpricelist' => $priceList->id,
                    //     'idproduct' => $id,
                    //     'idcompany' => $params['idcompany'],
                    // ]);
                    // $detail->fresh();
                }

                if (!empty($detail)) DetailPriceListProduct::insert($detail);
            }

            switch ($params['type']) {
                case '2':
                    foreach ($arrayBranchOffices as $idbranchoffice) {
                        $branchOffice = BranchOffice::activeForID($idbranchoffice)->first();
                        DetailPriceListBranchOffice::create([
                            'idpricelist' => $priceList->id,
                            'idbranchoffice' => $branchOffice->id,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                case '3':
                    foreach ($arraySalesman as $idsalesman) {
                        $salesman = Salesman::activeForID($idsalesman)->first();
                        DetailPriceListSalesman::create([
                            'idpricelist' => $priceList->id,
                            'idsalesman' => $salesman->id,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                case '4':
                    foreach ($arraySegments as $idsegment) {
                        $segment = Segment::activeForID($idsegment)->first();
                        DetailPriceListSegment::create([
                            'idpricelist' => $priceList->id,
                            'idsegment' => $segment->id,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                case '5':
                    $suppliers = Supplier::active()
                        ->whereIn('id', $arraycustomers)
                        ->where('idcompany', $params['idcompany'])
                        ->get()
                        ->keyBy('id');
                
                    $dataToInsert = [];
                    foreach ($arraycustomers as $idcustomer) {
                        if (isset($suppliers[$idcustomer])) {
                            $dataToInsert[] = [
                                'idpricelist' => $priceList->id,
                                'idcustomer' => $suppliers[$idcustomer]->id,
                                'idcompany' => $params['idcompany'],
                            ];
                        }
                    }
                
                    if (!empty($dataToInsert)) {
                        DetailPriceListCustomer::insert($dataToInsert);
                    }
                    break;
                default:
                    break;
            }

            DB::commit();
            return $this->successResponse('Lista de precio creada satisfactoriamente.', $priceList);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la creación de una lista de precio.', $th->getMessage());
        }
    }

    public function importExcel($params)
    {
        DB::beginTransaction();
        try {
            $file = $params['excel_import'];

            Excel::import(new PriceListDataImport($params), $file);

            DB::commit();
            return $this->successResponse('OK', 'Datos importados correctamente.');
        } catch (\throwable $th) {
            throw $th;
            return $this->externalError('durante la importación de Lista de precio', $th->getMessage());
        }
    }

    public function addProducts($params)
    {
        DB::beginTransaction();
        try {

            $priceList = PriceList::activeForID($params['idpricelist'])->first();
            if (!$priceList) return $this->errorResponse('No se encontró la lista de precios.', 400);

            $products = $params['products'] ?? [];
            $productsAdd = 0;
            if(sizeof($products) > 0 ){
                foreach ($products as $product) {
                    $productModel = Product::where('id', $product['id'])->where('status', 1)->first();
                    $price = $product['price'] ?? $productModel->price;
                    $cost = $product['cost'] ?? $productModel->cost;

                    $exitsProducts = DetailPriceListProduct::where('idpricelist', $priceList->id)->where('idproduct', $productModel->id)->where('status', 1)->first();

                    if(!$exitsProducts){
                        $detail = DetailPriceListProduct::create([
                            'price' => $price,
                            'cost' => $cost,
                            'stock' => $product['stock'],
                            'subtotal' => $price * $product['stock'],
                            'discount' => $product['discount'] ?? 0,
                            'idpricelist' => $priceList->id,
                            'idproduct' => $product['id'],
                            'idcompany' => $params['idcompany'],
                        ]);
                        $detail->fresh();

                        $productsAdd = $productsAdd + 1;
                    }
                }
            }

            $priceList->quantity_products = $priceList->quantity_products + $productsAdd;
            $priceList->save();

            DB::commit();
            return $this->successResponse('Productos agregados satisfactoriamente.', $priceList);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante el agregado de productos a una lista de precio.', $th->getMessage());
        }
    }

    public function duplicate($params)
    {
        DB::beginTransaction();
        try {
            $codeExisting = PriceList::code($params['code'])->active()->first();
            if($codeExisting) return $this->errorResponse('El código ya se encuentra registrado.', 400);

            $nameExisting = PriceList::code($params['name'])->active()->first();
            if($nameExisting) return $this->errorResponse('El nombre ya se encuentra registrado.', 400);

            $priceList = PriceList::activeForID($params['idpricelist'])->first();
            if (!$priceList) return $this->errorResponse('No se encontró la lista de precios.', 400);

            $detailproducts = DetailPriceListProduct::where('idpricelist', $priceList->id)->where('status', 1)->get();

            $currentDate = Carbon::now()->format('Y-m-d');
            $iduser = Auth::user()->id;

            $newpriceList = PriceList::create([
                'code' => $params['code'],
                'name' => $params['name'],
                'description' => $priceList->description,
                'creation_date' => $currentDate,
                'validity_date' => $priceList->validity_date,
                'document_state' => $priceList->document_state,
                'quantity_products' => $priceList->quantity_products,
                'type' => $priceList->type,
                'discounttype' => $priceList->discounttype,
                'max_desc_item' => $priceList->max_desc_item,
                'max_desc_global' => $priceList->max_desc_global,
                'created_by' => $iduser,
                'total' => $priceList->total,
                'status' => $priceList->status,
                'idcompany' => $priceList->idcompany,
            ]);
            $newpriceList->save();

            if(sizeof($detailproducts) > 0 ){
                foreach ($detailproducts as $detail) {
                    $detail = DetailPriceListProduct::create([
                        'price' => $detail->price,
                        'cost' => $detail->cost,
                        'stock' => $detail->stock,
                        'subtotal' => $detail->subtotal,
                        'discount' => $detail->discount,
                        'idpricelist' => $newpriceList->id,
                        'idproduct' => $detail->idproduct,
                        'idcompany' => $detail->idcompany,
                    ]);
                    $detail->fresh();
                }
            }

            switch ($priceList->type) {
                case '2':
                    $detailbranchoffice = DetailPriceListBranchOffice::where('idpricelist', $priceList->id)->where('status', 1)->get();
                    foreach ($detailbranchoffice as $detail) {
                        DetailPriceListBranchOffice::create([
                            'idpricelist' => $newpriceList->id,
                            'idbranchoffice' => $detail->idbranchoffice,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                case '3':
                    $detailsalesman = DetailPriceListSalesman::where('idpricelist', $priceList->id)->where('status', 1)->get();
                    foreach ($detailsalesman as $detail) {
                        DetailPriceListSalesman::create([
                            'idpricelist' => $newpriceList->id,
                            'idsalesman' => $detail->idsalesman,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                case '4':
                    $detailsegment = DetailPriceListSegment::where('idpricelist', $priceList->id)->where('status', 1)->get();
                    foreach ($detailsegment as $detail) {
                        DetailPriceListSegment::create([
                            'idpricelist' => $newpriceList->id,
                            'idsegment' => $detail->idsegment,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                case '5':
                    $detailcustomer = DetailPriceListCustomer::where('idpricelist', $priceList->id)->where('status', 1)->get();
                    foreach ($detailcustomer as $detail) {
                        DetailPriceListCustomer::create([
                            'idpricelist' => $newpriceList->id,
                            'idcustomer' => $detail->idcustomer,
                            'idcompany' => $params['idcompany'],
                        ]);
                    }
                    break;
                default:
                    break;
            }

            DB::commit();
            return $this->successResponse('Lista de precio duplicada satisfactoriamente.', $priceList);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la duplicidad de una lista de precio.', $th->getMessage());
        }
    }

    public function update($id, $params)
    {
        DB::beginTransaction();
        try {

            # Verificar validez Lista de precio
            $validate = $this->verifyList($id);
            if (!$validate->original['status']) return $validate;

            $$nameExisting = PriceList::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 = PriceList::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);

            if ($params['type'] == 2 && !$params['idbranchoffice']) return $this->errorResponse('La sucursal es obligatoria.', 400);

            $priceList = PriceList::find($id);
            $priceList->code = $params['code'];
            $priceList->name = $params['name'];
            $priceList->description = $params['description'];
            $priceList->validity_date = $params['validity_date'];
            $priceList->price = $params['price'];
            $priceList->alternativeprice = $params['alternativeprice'];
            $priceList->save();

            DB::commit();
            return $this->successResponse('Lista de precio actualizada satisfactoriamente.', $priceList);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la actualización de una lista de precio.', $th->getMessage());
        }
    }

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

            # Validar si existe una general
            $validateGeneral = PriceList::where('id', '<>', $id)->where('type', 1)->active()->get();
            if(count($validateGeneral) == 0) return $this->errorResponse('Debes de tener por lo menos una lista de precio general.', 400);

            $pricelist = PriceList::find($id);
            $pricelist->status = 2;
            $pricelist->save();

            DB::commit();
            return $this->successResponse('Lista de precio eliminada satisfactoriamente.', $pricelist);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la eliminación de una lista de precio.', $th->getMessage());
        }
    }

    private function verifyList($idlist)
    {
        $priceList = PriceList::where('id', $idlist)->where('status', 1)->first();
        if (!$priceList) return $this->errorResponse('No se encontró la lista de precios.', 400);

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