<?php

namespace App\Http\Controllers\Web;

use App\Helpers\LoopDetails;
use App\Http\Controllers\Controller;
use App\Http\Controllers\LoopUserController;
use App\Http\Requests\LoopRequest;
use App\Invoice;
use App\Loop;
use App\LoopGroup;
use App\LoopGroupUser;
use App\LoopGroupUserPaid;
use App\Notifications\LoopUserNotification;
use App\User;
use App\UserWallet;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class LoopController extends Controller
{
    private $view = 'web.loops.';

    private $currentLoop;
    /**
     * Get the loop of the current month, if it dose not exist, create one
     */
    public function __construct(){
        $this->currentLoop= Loop::firstOrCreate(['date'=>date('Y-m-1')]);
    }

    public function index(Request $request): View
    {
        // $userLoops= User::with('loop_groups.loop')->find(Auth::id())->toArray();
        $userLoops= User::with('loop_group_users.loop_group')->find(Auth::id())->toArray();
        $prevLoops= [];
        $currentLoops= [];
        $registeredInCurrentLoop= false;
        $currentLoop= [];
        // dd($userLoops);
        if ($userLoops) {
            foreach ($userLoops['loop_group_users'] as $loop) {
                $loopDate= date('Y-m-1', strtotime($loop['created_at']) );
                $loopPeriod= $loop['period'];
                $loopEndDateTime= strtotime("+{$loopPeriod} months", strtotime($loopDate));
                $loopEndDate= date('Y-m-d', $loopEndDateTime);
                $loopDetails= [
                    'id'=> $loop['loop_group']['loop_id'],
                    'month'=> date('M', strtotime($loopDate)),
                ];
                // dd(time() < $loopEndDateTime);
                if (time() < $loopEndDateTime && 'active' == $loop['status']) {
                    $currentLoops[]= $loopDetails;
                } else {
                    $prevLoops[]= $loopDetails;
                }
                if ($this->currentLoop->id == $loop['loop_group']['loop_id']) {
                    $registeredInCurrentLoop= true;
                }
                // dd($loopDate, $loopPeriod, $loopEndDate, $loopDetails);
            }
        }

        if ($registeredInCurrentLoop == false) {
            $currentLoop= [
                'month'=> date('M'),
                'end_date'=> date('Y-m-1 00:00:00', strtotime('+1 months'))
            ];
        }
        // dd($currentLoops);
        // dd($userLoops);
        return view($this->view.'index', compact('currentLoops', 'prevLoops', 'currentLoop'));
    }

    public function loopDetails(Request $request)//: ?View|RedirectResponse
    {
        $loopId= $request->loop_id ?? $this->currentLoop->id;

        // DB::enableQueryLog(); // Enable query log

        $query= Loop::where('loops.id', $loopId)
        ->select('loops.date as loop_date', 'loop_groups.*', 'loop_group_users.*', 'loop_group_users.id as loop_group_user_id')
        ->join('loop_groups', 'loop_groups.loop_id', '=', 'loops.id')
        ->join('loop_group_users', 'loop_groups.id', '=', 'loop_group_users.loop_group_id')
        ->where('loop_group_users.user_id',Auth::id())
        ->first();
        // dd(DB::getQueryLog());
        if( ! $query ) {
            return redirect()->route('loops.available');
        }
        $loopDetails= $query->toArray();
        // dd($loopDetails);

        $data= LoopDetails::loopUserInfo($loopDetails);
        // dd($data);
        return view($this->view.'details', $data);
    }

    /**
     * Call the current Loop
     * Get Loop Groups where sum(loop group users.share)< loop_group.setting.max_budget
     */

    public function available()//: ?View|RedirectResponse
    {
        $currentLoop= $this->currentLoop;
        $registeredInGroup= Auth::user()->loop_groups()->pluck('loop_groups.loop_id')->contains($currentLoop->id);

        if ($registeredInGroup) {
            return redirect()->route('loops.details');
        }
        // dd($registeredInGroup);
        // dd($currentLoop->toArray());
        // DB::enableQueryLog(); // Enable query log
        // Check Loop groups is exists
        $loopGroups= LoopGroup::where('loop_id', $currentLoop->id)->get()->toArray();
        // dd($loopGroups);
        if (!$loopGroups) {
            $loopGroupsSettings= json_decode( settings('group_settings'), true);
            // dd($loopGroupsSettings);
            foreach ($loopGroupsSettings as $period => $group) {
                // dd($group);
                $loopGroup['loop_id'] = $currentLoop->id;
                $loopGroup['setting'] = $group;
                // $loopGroup['period'] = $period;
                LoopGroup::create($loopGroup);
            }
        }
        // Get Groups

        $usersShareQuery= function($query){
            $query->from(with(new LoopGroupUser)->getTable())
            ->whereColumn('loop_group_id', 'loop_groups.id')
            ->selectRaw('SUM(share)');
        };

        $loopGroups= LoopGroup::where('loop_id', $currentLoop->id)
        ->whereRaw('json_extract(`setting`, \'$."max_budget"\') > json_extract(`setting`, \'$."real_budget"\')')
        // ->withGroupUsersShare()
        // ->where(function($query) use ($usersShareQuery) {
        //     return $query
        //     ->whereNull(DB::raw("(SELECT SUM(share) FROM loop_group_users lgu WHERE lgu.loop_group_id = loop_groups.id)"))
        //     ->orWhere('setting->max_budget', '>' , $usersShareQuery);
        // })
        ->get();
        // dd(DB::getQueryLog());
        // dd($loopGroups->toArray());

        return view($this->view.'available', compact('currentLoop', 'loopGroups'));
    }

    /**
     * Get the opened months in the requested group of the current loop
     * Opened month determined by check if the remain key of this month is ==-1 or more than the requested share
     */
    public function chekMonths(Request $request): JsonResponse
    {

        // DB::enableQueryLog(); // Enable query log

        $currentLoop= $this->currentLoop;
        $query= LoopGroup::where('loop_id', $currentLoop->id);

        if ($request->period) {
            $query->where('period', '=', $request->period);
        }

        $response= $query->first();
        // dd(DB::getQueryLog());
        // dd($response->toArray());
        $avaliableMonths= [];
        foreach ($response['setting']['months'] as $monthNumber => $monthSetting) {

            // dd($monthSetting['score'] , $request->user()->getScore());

            // fix months length is not more than period
            if ($monthNumber>= $request->period) {
                break;
            }

            // check the user's score is more than the month score
            if ($monthSetting['score'] >= $request->user()->getScore()) {
                break;
            }

            $class= 'enable';
            if ($monthSetting['remain'] == -1 || $monthSetting['remain']>= ($request->share * $request->period)) {
                $class='';
            }
            $monthNumber = date('m', strtotime("+" . $monthNumber . " months", strtotime($currentLoop->date)));
            $monthName = date('M', strtotime("+" . $monthNumber . " months", strtotime($currentLoop->date)));
            $newArray= [
                'month'=> $monthNumber,
                'name'=> $monthName,
                'class'=> $class
            ];
            $avaliableMonths[ $monthNumber ] = array_merge($monthSetting, $newArray);
        }
        // dd($avaliableMonths);
        return response()->json( $avaliableMonths );
    }


    /**
     * Phone Number Verfication Before cancel
     *
     */
    public function verify(Request $request)
    {
        $request->phone= $request->user()->phone;
        $request->email= $request->user()->email;
        // dd($request->all());
        $meta= [ 'loop_id'=> $request->loop_id ];
        if ('subscribe' == $request->type && session()->get('meta')) {
            $meta= $meta + session()->get('meta');
        }
        session()->put('meta', $meta);
        // dd($meta);
        $request->meta= json_encode($meta);

        return UserController::checkVerification($request);
    }

    /**
    * 1- Check user is not subscribed to this loop
    * 2- Validate request
    * Opened month determined by checking if the remain key of this month is ==-1 or more than the requested share
    */

    private static function validateRequest($request)
    {
        $currentLoop= $request->currentLoop;
        $registeredInGroup= Auth::user()->loop_groups()->pluck('loop_groups.loop_id')->contains($currentLoop->id);
        if ($registeredInGroup) {
            return ['success' => false, 'message'=> __('main.invalid_values')];
        }

        DB::enableQueryLog(); // Enable query log

        // dd($request->month);
        // $request->month= 3;
        $monthIndex= $request->month - date( 'm', strtotime($currentLoop->date) );
        // To fix issues fo negative values like choosing Feb. while the Loop start in Oct.
        if ($monthIndex < 0) {
            $monthIndex= 12 + $monthIndex;
        }

        // dd($monthIndex);

        $query= LoopGroup::where('loop_id', $currentLoop->id);
        $query->where('period', '=', $request->period);
        $query->selectRaw('id as loop_group_id, JSON_EXTRACT(`setting` , "$.months['. $monthIndex . ']") as month');
        // $query->selectRaw('id as loop_group_id, JSON_EXTRACT(`setting` , "$.months['. $monthIndex . '].remain") as remain');
        // $query->addSelectRaw('JSON_EXTRACT(`setting` , "$.months['. $monthIndex . '].score") as score');
        $query->addSelect('setting->max_budget as max_budget')->addSelect('setting->real_budget as real_budget');
        $loopGroup= $query->first();

        $loopGroup->month = json_decode($loopGroup->month);
        $remain= $loopGroup->month->remain;
        $score= (float) $loopGroup->month->score;
        $fees= (float) $loopGroup->month->fees;
        // dd(DB::getQueryLog());
        // dd($loopGroup->toArray(), $fees, $score, $remain, ($request->share * $request->period));
        // Invalid request
        if (
         !$loopGroup ||
         $request->user()->getScore() < $score ||
         ( ($loopGroup->max_budget - $loopGroup->real_budget) < $request->share ) ||
         ( $remain != -1 && $remain < ( $request->share * $request->period ) )
        ) {
            return ['success' => false, 'message'=> __('main.invalid_values')];
        }

        return [
            'success' => true,
            'loopGroup' => $loopGroup,
            'remain' => $remain,
            'score' => $score,
            'fees' => $fees,
            'monthIndex' => $monthIndex,
        ];

    }
    /**
     * subscribe to loop
     * 1- Validate request
     * 2- store the request in session to use it after validation
     * and send response
     *
     */

    public function subscribe(LoopRequest $request): JsonResponse
    {
        //
        $currentLoop= $this->currentLoop;
        $request->currentLoop= $currentLoop;
        $validateRequest= $this->validateRequest($request);
        // dd($validateRequest);
        if ($validateRequest['success'] == false) {
            return response()->json( ['success' => false, 'message'=> $validateRequest['message'] ?? __('main.invalid_values')], 422 );
        }

        $fees= $validateRequest['fees'];

        $share= $request->share;
        $period= $request->period;
        $totalShare= $share * $period;

        //Fees
        $settingFees= json_decode(settings('fees'), true);
        // dd($settingFees, $fees);
        $managmentFees= ceil($totalShare * $fees/100);
        $vatFees= ceil($share * $settingFees['vat_fees']/100);
        $governmentFees= (float)$settingFees['government_fees'];
        // Total
        $total= $share + $managmentFees + $vatFees + $governmentFees;
        // dd($settingFees, $managmentFees, $vatFees, $governmentFees, $total);

        $meta= [
            'loop_id' => $currentLoop->id,
            'amount' => $total ?? 0,
            'meta' => [
                'type' => 'subscribe',
                'loop_id' => $currentLoop->id,
                'period' => $period ?? 0,
                'share' => $share ?? 0,
                'month' => $request->month ?? 0,
                'managment_fees' => $managmentFees ?? 0,
                'vat_fees' => $vatFees ?? 0,
                'government_fees' => $governmentFees ?? 0,
                'total' => $total ?? 0,
            ]
        ];

        session()->put('meta', $meta);
        $redirect= route('loops.verify', ['loop_id'=> $currentLoop->id, 'type'=> 'subscribe']);
        return response()->json( ['success' => true, 'redirect'=> $redirect] );
    }

    /**
     * subscribe to loop
     *
     * The previuos step is in the next phase, but for now, the next step after validate the request is:
     * 2- Subscribe the user to the loop
     * 3- add user paid recorde to loog_group_user_paids for the current month
     * 4- decrease the amount of the 'remain' value of the selected month
     * 5- increase the amount of the 'real budget' value of the selected group
     * 6- create new invoice - make fees static for now as 150
     */

    public static function doSubscribe($request)
    {
        // dd($request->share, $request->period, $request->loop_id);
        // $currentLoop= Loop::find(['date'=>date('Y-m-1')]);
        $currentLoop= Loop::find($request->loop_id);
        // dd($currentLoop->toArray());
        $request->currentLoop= $currentLoop;
        $validateRequest= self::validateRequest($request);

        if ($validateRequest['success'] == false) {
            $data= [
                'error' => true,
                'route' => route('loops.available'),
                'success_notes' => $validateRequest['message'] ?? __('main.invalid_values'),
                // 'details_btn' => __('main.details'),
                'invoice_id' => '',
                'invoice' => [],
            ];
            // dd($data);
            return view('web.verification.success_verify', $data);
        }

        $loopGroup= $validateRequest['loopGroup'];
        $remain= $validateRequest['remain'];
        $monthIndex= $validateRequest['monthIndex'];
        $fees= $validateRequest['fees'];

        // dd($remain);

        $share= $request->share;
        $period= $request->period;
        $totalShare= $share * $period;

        // start subscribtion
        $encashment_month = date('Y-m-1', strtotime("+" . $monthIndex . " months", strtotime($currentLoop->date)));
        // dd($encashment_month);
        $data= [
            // 'email'=> Auth::user()->email,
            'loop_group_id'=> $loopGroup->loop_group_id,
            'user_id'=> Auth::id(),
            'share'=> $request->share,
            'period'=> $request->period,
            'encashment_month'=> $encashment_month,
            // 'monthIndex'=> $monthIndex,
            // 'code'=> rand(1000, 9999),
        ];
        $loopGroupUser= LoopGroupUser::create($data);

        // Insert paid in loop_group_user_paids
        $data= [
            'loop_group_user_id'=> $loopGroupUser->id,
            'month'=> date('m', strtotime($currentLoop->date)),
            'done' => true
        ];
        $loopGroupUserPaid= LoopGroupUserPaid::create($data);
        // Decrease remain value of the selected month
        $newRemain = ($remain >0 ? $remain : $loopGroup->max_budget);
        $newRemain -=  ($request->share * $request->period);
        // dd($newRemain);
        $query= LoopGroup::where('loop_id', $currentLoop->id)
            ->where('period', '=', $request->period)
            ->update(['setting'=> DB::raw("JSON_REPLACE(`setting`, '$.months[".$monthIndex."].remain', ".$newRemain.")")]);

        // Increase the real Budget Value
        $newRealBudget = $loopGroup->real_budget + $request->share ;

        $query= LoopGroup::where('loop_id', $currentLoop->id)
            ->where('period', '=', $request->period)
            ->update(['setting'=> DB::raw("JSON_REPLACE(`setting`, '$.real_budget', ".$newRealBudget.")")]);

        // Create Invoice

        $share= $request->share;
        $period= $request->period;
        $totalShare= $share * $period;

        //Fees
        $settingFees= json_decode(settings('fees'), true);
        // dd($settingFees, $fees);
        $managmentFees= ceil($totalShare * $fees/100);
        $vatFees= ceil($share * $settingFees['vat_fees']/100);
        $governmentFees= (float)$settingFees['government_fees'];
        // Total
        $total= $share + $managmentFees + $vatFees + $governmentFees;
        // dd($settingFees, $managmentFees, $vatFees, $governmentFees, $total);

        // subtract share from wallet
        $walletData= [
            'user_id' => $request->user()->id,
            'amount' => - $total,
            'description' => sprintf(__('loops.subscribe_in_loop'), date('F Y', strtotime($currentLoop->date)) ),
            'meta'=> [
                'type'=> 'pay_share',
                'loop_id'=> $currentLoop->id,
                'loop_group_id'=> $loopGroupUser->loop_group_id,
                'loop_group_user_id'=> $loopGroupUser->id,
                'period'=> $period,
                'months'=> 1,
                "share" => $share,
                "managment_fees" => $managmentFees,
                "government_fees" => $governmentFees,
                "vat_fees" => $vatFees,
                "total" => $total
            ]
        ];
        // dd($walletData);
        UserWallet::create($walletData);

        // Add Earn
        if ($encashment_month == date('Y-m-1')) {
            // Total Earn
            $totalEarn= $share * $period;
            // dd($share, $period, $totalEarn);

            // add earn from wallet
            $walletData= [
                'user_id' => $request->user()->id,
                'amount' => $totalEarn,
                'description' => sprintf(__('loops.cash_your_loop'), $totalEarn, date('F Y', strtotime($currentLoop->date)) ),
                'meta'=> [
                    'type'=> 'encashment',
                    'loop_id'=> $currentLoop->id,
                    'loop_group_id'=> $loopGroupUser->loop_group_id,
                    'loop_group_user_id'=> $loopGroupUser->id,
                    'period'=> $period,
                    'months'=> 1,
                    "share" => $share,
                    "total" => $totalEarn
                ]
            ];
            // dd($walletData);
            UserWallet::create($walletData);

            // set paid as done
            $loopGroupUser->get_paid= 1;
            $loopGroupUser->save();

            // send notification
            $notificationData= [
                'loop_group_id'=> $loopGroupUser->loop_group_id,
                'type' => $walletData['meta']['type'],
                'message' => $walletData['description'],
                'month' => date('m'),
                'months' => 1,
                'period' => $period,
                'share' => $share,
            ];
            $request->user()->notify(new LoopUserNotification($notificationData));
        }

        $invoiceData= [
            'code' => rand(10,99).time().rand(10,99),
            'loop_group_user_id'=> $loopGroupUser->id,
            'meta' => [
                "type" => 'subscribe',
                "share" => $share,
                "managment_fees" => $managmentFees,
                "vat_fees" => $vatFees,
                "government_fees" => $governmentFees,
                "total" => $total,
            ]
        ];
        // dd($invoiceData);
        $invoice= Invoice::create($invoiceData);

        $query= Loop::
        select('loops.date as loop_date', 'loop_groups.*', 'loop_group_users.*', 'loop_group_users.id as loop_group_user_id')
        ->join('loop_groups', 'loop_groups.loop_id', '=', 'loops.id')
        ->join('loop_group_users', 'loop_groups.id', '=', 'loop_group_users.loop_group_id')
        ->where('loop_group_users.id',$loopGroupUser->id)
        ->first();
        // dd(DB::getQueryLog());

        $loopDetails= $query->toArray();

        $details= LoopDetails::loopUserInfo($loopDetails);
        $data= [
            'route' => route('loops.details'),
            'success_notes' => __('loops.subscribe_success'),
            'details_btn' => __('main.details'),
            'invoice_id' => $invoice->code,
            'invoice' => $invoice,
            'loopDetails' => $details['loopDetails'],
            'subscribeDate' => $details['subscribeDate'],
            'encashMentDate' => $details['encashMentDate'],
            'totalFees' => $details['totalFees'],
            'period' => $details['loopDetails']['period'],
            'share' => $details['loopDetails']['share'],
            'totalShare' => $details['totalShare'],
            'totalPaid' => $details['loopDetails']['share'] + $details['totalFees'],

        ];
        // dd($data);
        return view('web.verification.success_verify', $data);
        // return response()->json( ['success' => true, 'data'=> $data ] );

    }

    /**
     * Pay Share
     * 1- check if there are months not paid
     * 2- Get the totalBalance after substract for paing for unpaid months
     * 3- if there is still unpaid months go to pay form
     * 4- if not
     */

    public function payShare(Request $request)
    {
        $query= LoopGroupUser::where('status', 'active')
        ->where('user_id', $request->user()->id)
        ->whereRaw("DATE_ADD(DATE_FORMAT(created_at,'%Y-%m-01'), INTERVAL `period` MONTH) >= CURDATE()")
        ->whereRaw("(SELECT loop_id FROM loop_groups lg WHERE lg.id = loop_group_users.loop_group_id LIMIT 1) = {$request->loop_id} ")
        ->selectRaw('*')
        ->addSelect(DB::raw("
        DATE_FORMAT(created_at,'%Y-%m-01') AS loop_date,
        MONTH(CURDATE()) AS current_month,
        (SELECT loop_id FROM loop_groups lg WHERE lg.id = loop_group_users.loop_group_id LIMIT 1) AS loop_id,
        (SELECT month FROM loop_group_user_paids lgup WHERE lgup.loop_group_user_id = loop_group_users.id ORDER BY created_at DESC LIMIT 1) AS last_paid_month"));

        $user= $query->first();
        // dd($user->toArray());
        $user= $user ? $user->toArray() : [];
        // dd(DB::getQueryLog());
        $lastMonth= $user['last_paid_month'] ? $user['last_paid_month'] : (date('m',strtotime($user['loop_date'].' -1 month')) );
        $unpaidMonths= $user['current_month'] - $lastMonth;
        if ($unpaidMonths<0) {
            $unpaidMonths = $unpaidMonths + 12;
        }

        if ($unpaidMonths == 0) {
            $data= [
                'route' => route('loops.details', ['loop_id'=> $request->loop_id]),
                'success_notes' => __('loops.subscribe_success'),
                'invoice_id' => '',
                'invoice' => []
            ];
            return view('web.verification.success_verify', $data);
        }

        $fees= settings('fees');
        $fees= $fees && json_decode($fees) ? json_decode($fees, true) : [];
        $settingDelayFees= (float) $fees['delay_fees'] ?? 0;

        $data= LoopUserController::payUnPaidShare($user, $settingDelayFees);
        $unpaidMonths= $data['unpaidMonths'];
        if ($unpaidMonths == 0) {
            $paidMonth= $data['paidMonth'];
            $delayFees= $data['delayFees'];
            $totalPaid= $data['totalPaid'];
            $totalBalance= $data['totalBalance'];

            $invoiceData= [
                'code' => rand(10,99).time().rand(10,99),
                'loop_group_user_id'=> $user['id'],
                'meta' => [
                    "type" => 'pay_share',
                    "share" => $user['share'],
                    "delay_fees" => $delayFees,
                    "total" => $totalPaid,
                ]
            ];
            // dd($invoiceData);
            $invoice= Invoice::create($invoiceData);

            $data= [
                'route' => route('loops.details', ['loop_id'=> $request->loop_id]),
                'success_notes' => __('loops.subscribe_success'),
                'invoice_id' => $invoice->code,
                'invoice' => $invoice,
            ];
            return view('web.verification.success_verify', $data);
        }

        // Go To Payment Page to Pay the remaing amount

    }
}
