<?php

namespace App\Http\Controllers\StockManagement;

use App\Http\Controllers\Controller;
use App\Models\ProductManagement\Product;
use App\Services\CartInstance;
use App\Services\CartService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Illuminate\Support\HtmlString;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File as FileRule;
use Illuminate\Validation\ValidationException;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use Yajra\DataTables\Exceptions\Exception;
use function Nette\Utils\firstKey;

class ImportationController extends Controller{

    const UPLOAD_PATH = "uploads-temps/stocks";
    const UPLOAD_SESSION_KEY = "tmp_uploaded";

    protected $cartService;

    public function __construct(){
        $this->cartService = new CartService(CartInstance::STOCK_IMPORTATIONS);
    }

    protected static function getUploadPath($filename = null){
        $adminId = auth("admin")->id();
        return public_path(self::UPLOAD_PATH."/$adminId/$filename");
    }


    public function listOnWarehouse(){
        $user = auth(activeGuard())->user();
        $datas = $user->importations()
                      ->get()
                   ;
        return datatables($datas)
            ->addIndexColumn()
            ->editColumn('qty', function ($row){
                return format_amount($row->qty);
            })
            ->addColumn('created_by', function ($row){
                return $row->createdBy->fullName ?? "";
            })
            ->editColumn('expired_at', function ($row){
                return format_date($row->expired_at);
            })
            ->editColumn('created_at', function ($row){
                return format_date($row->created_at);
            })
            ->editColumn('gap', function ($row){
                return format_amount($row->gap ?? 0);
            })
            ->editColumn('real_qty', function ($row){
                return format_amount($row->real_qty ?? 0);
            })
            ->editColumn('theoretical_qty', function ($row){
                return format_amount($row->theoretical_qty ?? 0);
            })
            ->addColumn('product_name', function ($row){
                return $row->product->name;
            })
            ->addColumn('product_category', function ($row){
                return $row->product?->category?->name;
            })
            ->only(["id","lot_id","qty","product_id","product_name","product_category",
                "expired_at",'created_by',"created_at","real_qty","theoretical_qty","gap"])
            ->make(true);
    }


    public function uploadFile(){

        try {
            $reader1 = new Xls(); // PhpOffice\PhpSpreadsheet\Reader\...()
            $reader = new Xlsx(); // PhpOffice\PhpSpreadsheet\Reader\...()
            $reader->setReadDataOnly(true);
            $reader->setReadEmptyCells(false);
            // retourne un objet de type PhpSpreadsheet en chargeant le fichier téléchargé
            $spreadsheet = $reader->load(public_path(self::UPLOAD_PATH));
            $datas  = $spreadsheet->getActiveSheet()->toArray(); // les données de la feuille active
        }catch (\Exception $exception){

        }
    }

    /** Importe les données d'un xls dans la session (cart-service)
     * @param Request $request
     * @return JsonResponse
     *
     */
    public function create(Request $request){
        $response = [
            'success' =>false,
            'message' => "Echec du téléchargement",
        ];

        try {

            $action = $request->action;
            $tmp_uploaded = session()->get(self::UPLOAD_SESSION_KEY);

            if ($action === "upload") {
                if(filled($tmp_uploaded)) File::delete(self::getUploadPath($tmp_uploaded['file_name']));

                $file = $request->file('upload');
                $file_name = $file->getClientOriginalName();
                $extension = $file->getClientOriginalExtension();

                $file_name = str_replace(".$extension","",$file_name);

//                $file_name= $filename.'-'.time().'.'.$extension;
                $file_name= $file_name.".".$extension;
                $upload_path = self::getUploadPath();
               // $path = public_path($upload_path);

                $rules = [
                    'file' => ["required" , FileRule::types(['xls',"xlsx"])],
                ];
                $data['file'] = $file;
                $validator = validator($data,$rules);

                if ($validator->fails()){
                    $response  = array_merge(dt_fields_errors($validator->errors()->messages()),$response);
                }else{
                    $file->move($upload_path, $file_name);
                    session()->put(self::UPLOAD_SESSION_KEY,[
                        'file_name' => $file_name,
                        'extension' => $extension,
                    ]);
                    $response['success'] = true;

                    $response['upload'] = ["id" => $file_name];
//                    $response['files'] = [
//                        "files" => [
//                            $tmp_uploaded_file_path => [
//                                "filename" => "",
//                                "original_name" => "",
//                                "size" => "",
//                                "directory" => "",
//                                "disk" => "",
//                                "url" => url($tmp_uploaded_file_path),
//                            ]
//                        ],
//                    ];
                    $response['message'] = "Upload Success";
                }
            }
            elseif ($action === "create"){

                $data = Arr::first($request->data);
                $file_has_headers = $data['file_has_headers']  ?? true;
                $file_path = self::getUploadPath($data['file']);

               // dd($file_path,$data);

                if (filled($tmp_uploaded) and File::exists($file_path)){

                    $XlsInstance = ($tmp_uploaded['extension'] === "xls") ? Xls::class : Xlsx::class;
                    $reader = (new $XlsInstance); // PhpOffice\PhpSpreadsheet\Reader\...()
                    $reader->setReadDataOnly(true);
                    $reader->setReadEmptyCells(false);
                    // retourne un objet de type PhpSpreadsheet en chargeant le fichier téléchargé
                    $spreadsheet = $reader->load($file_path);
                    $worksheet  = $spreadsheet->getActiveSheet()->toArray(); // les données de la feuille active


                    if ($file_has_headers){ // si entete
                        unset($worksheet[0]); // supprime la 1er ligne
                    }
                   // dd($worksheet);
                    foreach ($worksheet as $index => $row){
                        $inputs = [
                            'product_id' => (string) trim($row[0] ?? null),
                            'product_reference' => (string) trim($row[1] ?? null),
                            'product_name' => (string) trim($row[2] ?? null),
                            'lot_id' => (string) trim($row[3]),
                            'qty' => (float) trim($row[4] ?? 0),
                            'expired_at' => (float) trim($row[5] ?? 0),
                            'row' => $row,
                        ];

                        $errors = [];

                        $validation = $this->validateImportedRow($inputs);

                      //  dd($validation);

                        if (!$validation['success']){
                            $errors = dt_fields_errors($validation['errors'])['fieldErrors'];
                        }

                        $this->cartService->addItem( [
                            'id' => $inputs['product_id'],
                            'name' => $inputs['product_name'],
                            'qty' => $inputs['qty'],
                            'price' =>  0,
                            "options" => [
                                "lot_id" => $inputs['lot_id'],
                                "expired_at" => format_date($inputs['expired_at'],"Y-m-d"),
                                "product_reference" => $inputs['product_reference'],
                                "warehouse_id" => $data['warehouse_id'],
                                "errors" => $errors,
                                "created_at" => now()->format("Y-d-m H:i:s"),
                                "error_message" => filled($errors) ? $errors[0]['status'] : null ,
                            ]
                        ]);
                    }

                    $response['success'] = true;
                    $response['message'] = "All data was uploaded";
                    File::delete($file_path);
                    session()->forget(self::UPLOAD_SESSION_KEY);
                }

                else{
                    $response['message'] = "Fichier Introuvable";
                }
            }


        }catch (\Exception $exception){
            $response['message'] = $exception->getMessage();
        }
        return response()->json($response , $response['success'] ? 200 : 500);
    }


    /**
     * @param $data
     * @param null $column
     * @param bool $exception
     * @return array
     * @throws ValidationException
     * @throws \Throwable
     */
    protected function validateImportedRow($data, $column = null, $exception = false){
        $rules = [
            'product_id' => ["required", Rule::exists((new Product)->getTable(),"id")],
            'product_reference' => ["nullable",Rule::exists((new Product)->getTable(),"ref")],
            'product_name' => ["required",'string'],
            'qty' => ["required","numeric"],
            'lot_id' => ["nullable","string"],
            'expired_at' => ["nullable","date"],
            'row' => ["required","array","min:6","max:6"],
        ];

        $attributes = [
            'product_id' => __("Product Id"),
            'product_name' => __("Product Name"),
            'product_reference' => __("Product Reference"),
            'qty' => __("Qty"),
            'lot_id' => __("Lot Id"),
            'expired_at' => __("Expired Date"),
        ];


        if(filled($column)){
            if ($column === "expired_at") {
                $rules['scheduled_at'] = ['date',"after_or_equal:now"];
            }
            if ($column === "qty") {
                $rules['qty'] = ["required",'numeric'];
            }
        }

        $validator = validator($data,$rules,[],$attributes);

        $fails = $validator->fails(); // bool

       // $validated = $validator->validated(); // array

        $errors = $validator->errors()->all(); // array

//         if($validator->fails())   throw ValidationException::withMessages(['fieldErrors' => $errors]);
//         if($validator->fails())   return response()->json(['success' => false , dt_fields_errors($errors)],500);

        throw_if($fails and $exception,new \Exception($errors[0] ?? "Invalid data"));

        return [
            "success" => !$fails,
            "errors" => $errors,
           // "validated" => $validated,
        ];
    }

    /** Permet de modifier la valeur d'une colonne sur le tableau des importations
     * @param Request $request
     * @return JsonResponse
     */
    public function editColumn(Request $request){

        $response = ['success' => false, 'message' => false,];
        try {
            $action = $request->action; // (string) 'edit'
            $data  = $request->all()['data']; // (array)

            $rowsId = array_keys($data); // (array) ["12aoed87545454erfd","622ytegs87545tydrfd"]

            if ($action == "remove"){
                $response['success'] = $this->cartService->removeItems($rowsId);
            }
            elseif ($action == "edit"){
                if (count($rowsId) == 1) {
                    $rowId = Arr::firstKey($data);
                    $data = Arr::first($data);
                    $options = [];
                    $editData = [];

                    //Si on demande à modifié 'scheduled_at'
                    if (isset($data['expired_at'])){
                        $this->validateImportedRow($data,"expired_at",true);
                        $options['expired_at'] = $data['expired_at'];
                    }
                    if (isset($data['qty'])){
                        $this->validateImportedRow($data,"qty",true);
                        $editData['qty'] = $data['qty'];
                    }
                    if (isset($data['id'])){
                        $editData['id'] = $data['product_id'];
                    }
                    if (isset($data['product_name'])){
                        $editData['name'] = $data['product_name'];
                    }
                    if ($options){
                        $editData['options'] = $options;
                    }

                    if ($editData){
                        $response['success'] =  $this->cartService->updateItem($rowId,$editData);
                    }
                }
                else{

                    foreach ($data as $rowId => $row) {
                        if($request->filled("edit_column")) $this->validateImportedRow($row,$request->edit_column);
                        unset($row['edit_column']);
                        $this->cartService->updateItem($rowId,['options' => $row]);
                    }
                    $response['success'] = true;
                }

            }
        }catch (\Exception $exception){
            $response['message'] = $exception->getMessage();
        }

        return response()->json($response , $response['success'] ? 200 : 500);
    }

    public function removeImportedRow(Request $request){
        $response = ['success' => false, 'message' => false,];
        try {
            $rowIds = $request->rowIds;
           // dd($rowIds);
            $response['success'] =  $this->cartService->removeItems($rowIds);
        }catch (\Exception $exception){
            $response['message'] = $exception->getMessage();
        }

        return response()->json($response , $response['success'] ? 200 : 500);
    }


    /** Affiche les données extraites du fichier importé
     * @param Request $request
     * @return JsonResponse
     * @throws Exception
     */
    public function previewImportedData(Request $request){
        $warehouse_id = $request->warehouse_id;
        $rows = $this->cartService
                    ->getContent()
                    ->filter(fn ($row) => $row->options['warehouse_id'] === $warehouse_id)
                    ->sortBy('id');

        //dd($rows);

        return datatables($rows)
            ->setRowId('rowId')
            ->addIndexColumn()
            ->addColumn("expired_at", function($row){
                $expired_at =  $row->options['expired_at'];
                return $expired_at;
               // return filled($expired_at) ? format_date($expired_at,__("Y-m-d")) : null;
            })
            ->addColumn("product_id", fn($row)=> $row->id)
            ->editColumn("qty", fn($row)=> $row->qty)
            ->addColumn("product_name", fn($row)=> $row->name)
            ->addColumn("product_reference", fn($row)=> $row->options['product_reference'] ?? null)
            ->addColumn("lot_id", fn($row)=> $row->options['lot_id'] ?? null)
            ->addColumn("warehouse_id", fn($row)=> $row->options['warehouse_id'] ?? null)
            ->addColumn("error_message", fn($row)=> $row->options['error_message'] ?? null)
            ->addColumn("errors", fn($row)=> $row->options['errors'] ?? null)
            ->addColumn("actions",function ($row){
                $text = __("Delete");
                return new HtmlString("<a href='javascript:void(0)' class='action-click cursor-pointer text-underline text-danger btn-remove-row'>
                                       $text
                                        <small class='fa fa-trash'></small>
                                    </a>");
            })
            ->only(['rowId',"product_id","product_name","product_reference",
                "lot_id","expired_at","warehouse_id","actions","qty","error_message","errors"])
            ->make(true)
            ;
    }
}
