<?php

namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Requests\Admin\ProductStoreRequest;
use App\Http\Requests\Admin\ProductUpdateRequest;
use App\Models\Product;
use App\Models\ProductLot;
use App\Exceptions\Handler;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use App\Http\Resources\ProductResource;
use App\Http\Resources\ProductLotResource;
use Illuminate\Support\Facades\Validator;
use App\Rules\ProductLots;
use Illuminate\Validation\Rule;
use Symfony\Component\HttpFoundation\Response;

/**
 * @covers \ProductController
 */
class ProductController extends Controller{

    protected $table = 'products';

    /**
     * Store the product.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(ProductStoreRequest $request){

        $dimensions = array($request->length, $request->breadth,
            $request->height);
        sort($dimensions);
        $weight = $request->weight;

        $size_configuration_id = Product::getSizeConfigurationId($dimensions, $weight);
        // What if there's no such id?

        $metadata = json_encode([
            "created_by" => "admin"
        ],true);

        $stockarea_id = Product::getStockareaId();

        DB::beginTransaction(); //Start db transaction for rollback query when error
        try {
            $product = Product::create([
                'stockarea_id' => $stockarea_id,
                'metadata' => $metadata,
                'size_configuration_id' => $size_configuration_id,
                'length' => $request->length,
                'breadth' => $request->breadth,
                'height' => $request->height,
                'weight' => $request->weight,
                'value' => $request->value,
                'serial_number_scan' => $request->serial_number_scan,
                'sku' => $request->sku,
                'barcode' => $request->barcode,
                'resource_type' => $request->resource_type,
                'resource_id' => $request->resource_id,
                'reorder_point' => $request->reorder_point,
                'virtual_product' => $request->virtual_product,
                'hazardous_product' => $request->hazardous_product,
                'fragile_product' => $request->fragile_product,
                'status' => $request->status,
                'case_product' => $request->case_product,
                'units_in_case' => $request->units_in_case,
                'case_item_id' => $request->case_item_id,
                'lot_product' => $request->lot_product,
                'expiration_date' => $request->expiration_date,
                'description' => $request->description,
                'insured' => $request->insured,
                'packaging_type_id' => $request->packaging_type_id,
                'product_category_id' => $request->product_category_id,
            ]);

            // Add Product Lots
            if($request->lot_product){
                $product_lots = $request->product_lots;
                foreach($product_lots as $lot_number){
                    ProductLot::create([
                        'lot_number' => $lot_number,
                        'product_id' => $product->id,
                    ]);
                }
            }

            DB::commit();
            return new ProductResource($product);
        } catch (\Exception $e) {
            error_log("GAVE ME AN EXCEPTION");
            DB::rollBack();
            return response()->json(['error' => $e], 500);
        }
    }


    /**
     * Get the product with given stoackarea_id.
     *
     * @param int $stockarea_id
     * @return \Illuminate\Http\Response
     */
    public function show($stockarea_id){
        $validator = Validator::make(['stockarea_id' => $stockarea_id],
            [ 'stockarea_id' => ['required'] ],
            ['stockareaId.required' => 'category Stockarea Id is required required']
        );

        if($validator->fails()){
            return response()->json(['errors' => $validator->errors()], 422);
        }

        $product = Product::where('stockarea_id', $stockarea_id)->first();
        return new ProductResource($product);
    }


    /**
     * Get all the products.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(){
        return ProductResource::collection(Product::all());
    }


    /**
     * Store the product lots for the product with the given stockarea_id.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function storeProductLots(Request $request){
        $product = Product::where('stockarea_id', $request->stockarea_id)->first();
        $product_id = $product->id;
        $validator = Validator::make(
            [
                'stockarea_id' => $request->stockarea_id,
                'product_lots' => $request->product_lots,
            ],
            [
                'stockarea_id' => ['required'],
                'product_lots' => ['required','array'],
                'product_lots.*' => ['required', 'string', 'alpha_num', 'distinct',
                    Rule::unique('product_lots', 'lot_number')->where(function ($query) use($product_id) {
                        return $query->where('deleted_at', NULL)
                            ->where('product_id', $product_id);
                    })]
            ],
            [
                'stockareaId.required' => 'Stockarea Id is required required',
                'product_lots.required' => 'Product Lots is required',
                'product_lots.array' => 'Product Lots must be array',
                'product_lots.*.string' => 'Product Lot number must be an alphanumeric string',
                'product_lots.*.alpha_num' => 'Product Lot number must be an alphanumeric string',
                'product_lots.*.unique' => 'Product Lot number must be unique to the product',
                'product_lots.*.distinct' => 'Product Lot numbers for the product must be distinct',
            ]);

        if($validator->fails()){
            return response()->json(['errors' => $validator->errors()], 422);
        }

        $product_lots = $request->product_lots;

        DB::beginTransaction();
        try{
            foreach($product_lots as $lot_number){
                ProductLot::create([
                    'lot_number' => $lot_number,
                    'product_id' => $product->id,
                ]);
            }
            DB::commit();

            return ProductLotResource::collection(
                ProductLot::where('product_id', $product->id)
                ->wherein('lot_number', $product_lots)
                ->get());
        }
        catch(\Exception $e){
            DB::rollBack();
            return response()->json(['error' => $e], 500);
        }
    }


    /**
     * Delete the product with given stockarea_id.
     *
     * @param int $stockarea_id
     * @return \Illuminate\Http\Response
     */
    public function deleteProduct($stockarea_id){
        $validator = Validator::make(['stockarea_id' => $stockarea_id],
            ['stockarea_id' => ['required']],
            ['stockareaId.required' => 'Stockarea Id is required required']
        );

        if($validator->fails()){
            return response()->json(['errors' => $validator->errors()], 422);
        }

        DB::beginTransaction();
        try{
            Product::where('stockarea_id', $stockarea_id)->delete();
            DB::commit();
            return response('Deleted',Response::HTTP_OK);
        }
        catch(\Exception $e){
            DB::rollback();
            throw new \Askedio\SoftCascade\Exceptions\SoftCascadeLogicException($e->getMessage());
        }
    }


    /**
     * Update the product with given stockarea_id.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function update(ProductUpdateRequest $request){
        $product = Product::where('stockarea_id', $request->stockarea_id)->first();
        $product->fill($request->all());

        $dimensions = array($request->length, $request->breadth,
            $request->height);
        sort($dimensions);
        $weight = $request->weight;

        $size_configuration_id = Product::getSizeConfigurationId($dimensions, $weight);

        $product->size_configuration_id = $size_configuration_id;

        $metadata = (array)json_decode($product->metadata);
        // Add the updates field if not already there.
        if(!isset($metadata['updates'])){
            $metadata['updates'] = array();
        }
        // Append to the updates field in the metadata, updated_by and updated_at.
        array_push($metadata['updates'], [
            "updated_by" => "admin",
            "updated_at" => now(),
        ]);

        $product->metadata = json_encode($metadata);
        $product->save();

        // Update product Lots
        if($request->lot_product == TRUE){
            $product_lots = $request->product_lots;
            foreach($product_lots as $product_lot){
                ProductLot::where('id', $product_lot['product_lot_id'])
                    ->update(['lot_number' => $product_lot['lot_number']]);
            }
        }
        return new ProductResource($product);
   }


    /**
     * Delete the product lots for the product with given stockarea_id.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function deleteProductLots(Request $request){
        $product = Product::where('stockarea_id', $request->stockarea_id)->first();
        $product_id = $product->id;

        $validator = Validator::make(
            [
                'stockarea_id' => $request->stockarea_id,
                'product_lots' => $request->product_lots,
            ],
            [
                'stockarea_id' => ['required'] ,
                'product_lots' => ['required','array'],
                'product_lots.*' => ['required', 'string', 'alpha_num', 'distinct',
                    Rule::exists('product_lots', 'lot_number')->where(function ($query) use($product_id) {
                        return $query->where('product_id', $product_id);
                    })]
            ],
            [
                'stockareaId.required' => 'Stockarea Id is required required',
                'product_lots.required' => 'Product Lots is required',
                'product_lots.array' => 'Product Lots must be array',
                'product_lots.*.required' => 'Product lots array must not be empty.',
                'product_lots.*.string' => 'Product Lot number must be an alphanumeric string',
                'product_lots.*.alpha_num' => 'Product Lot number must be an alphanumeric string',
                'product_lots.*.exists' => 'The product lot numbers must exist for the product',
                'product_lots.*.distinct' => 'The product lot numbers for the product must be distinct',
            ]
        );

        if($validator->fails()){
            return response()->json(['errors' => $validator->errors()], 422);
        }
        $product_lots = $request->product_lots;

        DB::beginTransaction();
        try{
            ProductLot::where('product_id', $product_id)
                ->wherein('lot_number', $product_lots)
                ->delete();
            DB::commit();
            return response('Deleted',Response::HTTP_OK);
        }
        catch(\Exception $e){
            DB::rollBack();
            return response()->json(['error' => $e], 500);
        }
   }
}
