<?php

namespace App\Repositories\Member\VoucherEvent;

use App\Models\Voucher;
use App\Models\VoucherEvent;
use App\Models\VoucherClaim;
use App\Models\Customer;
use App\Models\CustomerPoint;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use Carbon\Carbon;

class VoucherEventRepository
{
    public function getList($request)
    {
        $model = VoucherEvent::where('redeem_point', '>', 0)->orderBy('created_at','desc')->paginate($request->limit);

        return $model;
    }

    public function detail($id)
    {
        $model = VoucherEvent::findOrFail($id);
        return $model;
    }

    public function items($id, $request)
    {
        $model = VoucherEvent::findOrFail($id);

        $limit = $request->input('limit', 10);
        if ($limit <= 0) {
            $limit = 10;
        }

        $query = DB::table('voucher_items')
        ->leftJoin('item_reference', 'item_reference.id', '=', 'voucher_items.item_reference_id')
        ->leftJoin('items', 'item_reference.item_id', '=', 'items.id')
        ->leftJoin('item_variants', 'item_reference.item_variant_id', '=', 'item_variants.id')
        ->where('voucher_event_id', $model->id)
        ->select('item_reference.number as reference_number', DB::raw('COALESCE(item_variants.description, items.name) as name'));

        $data = $query->paginate($limit);

        return $data;
    }

    public function createVoucher($voucher, $customer, $user, $description, $expired_at, $min_sales = null){
        DB::beginTransaction();
        try{
            $voucherExist = Voucher::where('voucher_event_id', $voucher->id)
                ->whereNull('used_at')->where(function($query){
			$query->whereNull('expired_at')
->orWhere('expired_at',">=", Carbon::now());
})
                ->where('customer_id', $customer->id)
                ->first();

            if ($voucherExist != null){
                DB::rollback();

                return $voucherExist;
                // throw ValidationException::withMessages([
                //     "point" => "Voucher ini sudah pernah di claim"
                // ]);
            }

            $number = $this->generateVoucher($voucher->nominal);
            $nominal = (float) @$voucher->nominal;

            $model = Voucher::create([
                'number' => $number,
                'voucher_event_id' => $voucher->id,
                'nominal' => $nominal,
                'customer_id' => $customer->id,
                'expired_at' => $expired_at,
                "description" => $description,
                'min_sales' => $min_sales
            ]);

            VoucherClaim::create([
                'time' => now(),
                'voucher_id' => $model->id,
                'claimable_id' => $model->id,
                'claimable_type' => get_class($model),
                'claimer_id' => $customer->id,
                'claimer_type' => get_class($customer),
                'user_id' => @$user->id
            ]);

            DB::commit();
            return $model;
        }catch(\Exception $e){

            DB::rollback();
            throw $e;
        }

    }

    public function redeem($id)
    {
        $model = DB::transaction(function () use ($id) {

            $voucher = VoucherEvent::findOrfail($id);

            $number = $this->generateVoucher($voucher->nominal);

            if ($voucher->nominal == null || $voucher->nominal == 0) {
                $nominal = 0;
            }else {
                $nominal = $voucher->nominal;
            }

            $customer = Customer::where('user_id', auth()->user()->id)->firstOrFail();
            $point = DB::select("SELECT SUM(point) as point FROM customer_points WHERE customer_id = ? ", [$customer->id]);
            $point = (float) @$point[0]->point;

            if ($point < $voucher->redeem_point) {
                throw ValidationException::withMessages([
                    "point" => "Point anda tidak mencukupi"
                ]);
            }

            $model = Voucher::create([
                'number' => $number,
                'voucher_event_id' => $voucher->id,
                'nominal' => $nominal,
                'customer_id' => $customer->id,
                'expired_at' => Carbon::now()->addMonth(3),
                "description" => "REDEEM VOUCHER",
            ]);

            VoucherClaim::create([
                'time' => now(),
                'voucher_id' => $model->id,
                'claimable_id' => $model->id,
                'claimable_type' => get_class($model),
                'user_id' => auth()->user()->id
            ]);

            $customer = Customer::where('user_id', auth()->user()->id)->firstOrFail();

            $this->redeemPoint($customer->id, $voucher->redeem_point, "Redeem point for ".$model->description, $model);

            return $model;
        });

        return $model;
    }

    public function claim($id, $customer, $expired_at, $ref)
    {
        $model = DB::transaction(function () use ($id, $customer, $expired_at, $ref) {

            $event = VoucherEvent::findOrfail($id);

            $number = $this->generateVoucher($event->nominal);
            $nominal = (float) @$event->nominal;

            $model = Voucher::create([
                'number' => $number,
                'voucher_event_id' => $event->id,
                'nominal' => $nominal,
                'customer_id' => $customer->id,
                'expired_at' => $expired_at,
                "description" => "FREE VOUCHER ". $event->name,
            ]);

            $user = auth()->user();

            $claim = VoucherClaim::create([
                'time' => now(),
                'voucher_id' => $model->id,
                'claimable_id' => $ref->id,
                'claimable_type' => get_class($ref),
                'user_id' => @$user->id ?? 0
            ]);

            $model->fill([
                "reference_issued_id" => $claim->id,
                "reference_issued_type" => get_class($claim)
            ]);
            $model->save();

            return $model;
        });

        return $model;
    }

    private function redeemPoint($customer_id, $point_out, $title, $ref){

        $point = new CustomerPoint;
        $point->customer_id = $customer_id;
        $point->point = $point_out * -1;
        $point->description = $title;
        $point->reference_id = $ref->id;
        $point->reference_type = get_class($ref);
        $point->save();
    }

    private function generateVoucher($nominal)
    {
        $code = "BLJ";
        if ($nominal == 2000000) {
            $code = "2JT";
        } else if ($nominal == 1000000) {
            $code = "1JT";
        } else if ($nominal == 1500000) {
            $code = "1.5JT";
        } else if ($nominal == 2500000) {
            $code = "2.5JT";
        } else if ($nominal == 500000) {
            $code = "500RB";
        } else if ($nominal == 750000) {
            $code = "750RB";
        } else if ($nominal == 250000) {
            $code = "250RB";
        } else if ($nominal == 100000) {
            $code = "100RB";
        } else if ($nominal == 50000) {
            $code = "50RB";
        } else if ($nominal == 3000000) {
            $code = "3JT";
        }
        $voucher = null;
        $iter = 0;
        while ($voucher == null) {
            $new_code = strtoupper("EV/" . $code . "/" . date("Y") . "/" . bin2hex(openssl_random_pseudo_bytes(3)));
            $exists = Voucher::where("number", $new_code)->first();
            $voucher = $exists ? null : $new_code;
        }
        return $voucher;
    }

}
