<?php

namespace App\Repositories;

use App\Notifications\NewUserRegisteredNotification;
use App\StripeUser;
use App\UserSubscription;
use App\User;
use Carbon\Carbon;
use Faker\Factory as Faker;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Excel;
use League\Flysystem\FileNotFoundException;
use Spatie\ImageOptimizer\OptimizerChainFactory;


class UserRepository implements RepositoryInterface
{

    private const PUBLIC_PROFILE_IMAGES_FOLDER = "storage/user-profile-images";

    public static function all(array $filters = []) {
        $users = null;
        if(sizeof($filters) == 0) {
            $users = User::all();
        }
        else {
            $whereClauses = [];
            foreach($filters as $key => $val) {
                if(is_numeric($val)) {
                    array_push($whereClauses, [[$key, $val]]);
                }
                else {
                    array_push($whereClauses, [[$key, 'like', "%$val%"]]);
                }
            }
            $users = User::where($whereClauses[0]);
            unset($whereClauses[0]);
            foreach($whereClauses as $clause) {
                $users = $users->orWhere($clause);
            }
            $users = $users->get();
        }

        return $users;
    }

    public static function create(array $data) {
        $user = User::create($data);

        $user->notify((new NewUserRegisteredNotification($user))->delay(Carbon::now()->addSeconds(5)));

        return $user;
    }

    public static function update(array $data, $id) {
        $user = User::findOrFail($id);
        $user->update($data);
        if(isset($data["favorite_workouts_ids"])) {
            $user->favorite_workouts()->sync($data["favorite_workouts_ids"]); //actualitzem relació
        }
        return User::findOrFail($id);
    }

    public static function delete($id){
        return User::destroy($id);
    }

    public static function find($id){
        return User::findOrFail($id);
    }

    public static function sessions($id) {
        return User::findOrFail($id)->trainingSessions;
    }

    public static function benchmarks($id) {
        return User::findOrFail($id)->user_benchmarks;
    }

    /**
     * @param $id
     * @param null $company_id
     * @param null $box_id. Pot ser un array!
     * @return Array UserSubscription. Retorna una llista de suscripcions que tens per una companyia o per un box.
     * Per tal que aquest mètode funcioni bé, els pricing_box han d'estar ben relacionats. Si esperes que una tarifa
     * que identifiques amb box_id et retorni dades de la companyia (si en tens autoritzacio), ha d'estar la relacio
     * feta a pricing_box
     *
     * MÈTODE MOLT CRITIC!!!! S'UTILITZA PER LES AUTORITZACIONS!!!! VIGILAR MOLT A L'HORA DE TOCAR-LO I PROVAR-LO MOLT
     *
     */
    public static function userSubscriptions($user_id, $company_id = null, $box_id = null, array $options = []) {
        $active = isset($options["active"]) && $options["active"] == true;
        $company_active = isset($options["company_active"]) && $options["company_active"] == true;
        $user_subscriptions = User::findOrFail($user_id)->user_subscriptions;
        if($company_active) {
            if($active) {
                $subscriptions_temp = $user_subscriptions;
                $user_subscriptions = [];
                if($company_id) {
                    foreach($subscriptions_temp as $s) {
                        if($s->active == true  &&  $company_id == $s->pricing->company_id  &&  $s->company->active_plan!=null)
                            array_push($user_subscriptions, $s);
                    }
                }
                elseif($box_id) {
                    foreach($subscriptions_temp as $s) {
                        if(!is_array($box_id)) $box_id = [ $box_id ];
                        foreach($box_id as $id) {
                            if ($s->active == true && in_array($id, $s->box_ids) && $s->company->active_plan != null) {
                                array_push($user_subscriptions, $s);
                                break;
                            }
                        }
                    }
                }
                else {
                    foreach($subscriptions_temp as $s) {
                        if($s->active == true  &&  $s->company->active_plan!=null)
                            array_push($user_subscriptions, $s);
                    }
                }
            }
            else {
                if($company_id) {
                    $subscriptions_temp = $user_subscriptions;
                    $user_subscriptions = [];
                    foreach($subscriptions_temp as $s) {
                        if($company_id == $s->pricing->company_id  &&  $s->company->active_plan!=null)
                            array_push($user_subscriptions, $s);
                    }
                }
                elseif($box_id) {
                    $subscriptions_temp = $user_subscriptions;
                    $user_subscriptions = [];
                    foreach($subscriptions_temp as $s) {
                        if(!is_array($box_id)) $box_id = [ $box_id ];
                        foreach($box_id as $id) {
                            if ($s->active == true  &&  in_array($id, $s->box_ids)  &&  $s->company->active_plan!=null) {
                                array_push($user_subscriptions, $s);
                                break;
                            }
                        }
                    }
                }
            }
        }
        else {
            if($active) {
                $subscriptions_temp = $user_subscriptions;
                $user_subscriptions = [];

                if($company_id) {
                    foreach($subscriptions_temp as $s) {
                        if($s->active == true  &&  $company_id == $s->pricing->company_id)
                            array_push($user_subscriptions, $s);
                    }
                }
                elseif($box_id) {
                    foreach($subscriptions_temp as $s) {
                        if(!is_array($box_id)) $box_id = [ $box_id ];
                        foreach($box_id as $id) {
                            if ($s->active == true  &&  in_array($id, $s->box_ids)) {
                                array_push($user_subscriptions, $s);
                                break;
                            }
                        }
                    }
                }
                else {
                    foreach($subscriptions_temp as $s) {
                        if($s->active == true) array_push($user_subscriptions, $s);
                    }
                }
            }
            else {
                if($company_id) {
                    $subscriptions_temp = $user_subscriptions;
                    $user_subscriptions = [];
                    foreach($subscriptions_temp as $s) {
                        if($company_id == $s->pricing->company_id)
                            array_push($user_subscriptions, $s);
                    }
                }
                elseif($box_id) {
                    $subscriptions_temp = $user_subscriptions;
                    $user_subscriptions = [];
                    foreach($subscriptions_temp as $s) {
                        if(!is_array($box_id)) $box_id = [ $box_id ];
                        foreach($box_id as $id) {
                            if ($s->active == true  &&  in_array($id, $s->box_ids)) {
                                array_push($user_subscriptions, $s);
                                break;
                            }
                        }
                    }
                }
            }
        }

        return $user_subscriptions;
    }

    public static function payments($id) {
        return User::findOrFail($id)->payments();
    }

    public static function subscriptionPayments($id) {
        return User::findOrFail($id)->subscriptionPayments;
    }

    public static function orderPayments($id) {
        return User::findOrFail($id)->orderPayments;
    }

    public static function paymentsByBox($id, $box_id) {
        return array_filter(User::findOrFail($id)->payments(), function($payment) use(&$box_id) {
            return $payment->box->id == $box_id;
        });
    }

    public static function subscriptionPaymentsByBox($id, $box_id) {
        return array_filter(User::findOrFail($id)->subscriptionPayments, function($payment) use(&$box_id) {
            return $payment->box->id == $box_id;
        });
    }

    public static function orderPaymentsByBox($id, $box_id) {
        return array_filter(User::findOrFail($id)->orderPayments, function($payment) use(&$box_id) {
            return $payment->box->id == $box_id;
        });
    }

    public static function cobrarCredits($session,$box_id,$user_id){

        $slug = TrainingTypeRepository::find($session->training_type_id)->slug;
        $subscription = UserRepository::find($user_id)->getUserSubscription($box_id);
        $type = "";

        //dd($subscription->id);
        if($slug=='open' && (!$subscription->open_counter || $subscription->open_counter>0)){
            if($subscription->open_counter) $subscription->open_counter = $subscription->open_counter - 1;
            $type = 'open';
        }else if($slug!='open' && (!$subscription->wod_counter || $subscription->wod_counter>0)){
            if($subscription->wod_counter) $subscription->wod_counter = $subscription->wod_counter - 1;
            $type = 'wod';
        }else if(!$subscription->total_counter || $subscription->total_counter>0){
            if($subscription->total_counter) $subscription->total_counter = $subscription->total_counter - 1;
            $type = 'total';
        }else{
            return false;
        }
        $credits = [
            "wod_counter" => $subscription->wod_counter,
            "open_counter" => $subscription->open_counter,
            "total_counter" => $subscription->total_counter,
        ];


        $session->users()->attach($user_id, ["type" => $type]);
        if($session->credits) UserSubscriptionRepository::update($credits,$subscription->id);
        return true;
    }

    public static function retornarCredits($session,$box_id,$user_id){

        $user = User::find($user_id);
        $subscription = $user->getUserSubscription($box_id);

        $user_trainingSession = $user->trainingSessions;

        $slug = false;
        foreach ($user_trainingSession as $ts) {
            if ( $ts['id'] == $session->id) $slug = $ts->pivot->type;
        }

        if ($slug) {
            //dd($subscription->id);
            if($slug=='open'){
                if ($subscription->open_counter) $subscription->open_counter = $subscription->open_counter + 1;
            }else if($slug!='open' && $slug!='total'){
                if ($subscription->wod_counter) $subscription->wod_counter = $subscription->wod_counter + 1;
            }else if($slug=='total'){
                if ($subscription->total_counter) $subscription->total_counter = $subscription->total_counter + 1;
            }else{
                return false;
            }
            $credits = [
                "wod_counter" => $subscription->wod_counter,
                "open_counter" => $subscription->open_counter,
                "total_counter" => $subscription->total_counter,
            ];
            $session->users()->detach($user_id);
            UserSubscriptionRepository::update($credits,$subscription->id);
            return true;

        } else return false;
    }

    public static function boxOrders($id) {
        return User::findOrFail($id)->boxOrders;
    }

    public static function favoriteExercises($id) {
        return User::findOrFail($id)->favorite_workouts;
    }

    public static function superUsers() {
        $temp = DB::table("subscriptions as s")
            ->select("u.*")
            ->leftJoin("users as u", "s.user_id", "u.id")
            ->leftJoin("roles as r", "r.id", "s.role_id")
            ->where("r.slug", "super_admin")
            ->distinct()
            ->get();

        //Ja ho se, es una cosa guarra
        $res = [];

        foreach($temp as $u) {
            array_push($res, UserRepository::find($u->id));
        }


        return $res;
    }

    public static function getStripeIdByCompanyId($user_id, $company_id)
    {
        $u = StripeUser::where([["user_id", $user_id], ["company_id", $company_id]])->first();
        if (!$u) throw new \Exception("Stripe user not found for that company");
        return $u->stripe_id;
    }

    public static function joinToNotifyTrainingsession($user_id,$session_id) {
        $session = TrainingSessionRepository::find($session_id);
        $session->usersToNotify()->attach($user_id);
    }

    public static function benchmarksWorkout($user_id,$workout_id) {
        return self::find($user_id)->user_benchmarks()->where('training_workout_id','=',$workout_id)->orderBy('created_at')->get();
    }

    public static function uploadProfileImage($id, UploadedFile $file) {
        if($file==null) throw new FileNotFoundException("No se ha proporcionado ninguna imagen.");

        $faker = Faker::create();
        $name = $faker->uuid . "." . $file->extension();
        $path = public_path(UserRepository::PUBLIC_PROFILE_IMAGES_FOLDER);

        //movem
        $path = $file->move($path, $name);

        //optimitzem
        $optimizerChain = OptimizerChainFactory::create();
        $optimizerChain->optimize($path);

        //fem url
        $url = url("/" . UserRepository::PUBLIC_PROFILE_IMAGES_FOLDER . "/" .  $name);

        $user = User::findOrFail($id);
        $user->url_profile_photo = $url;
        $user->save();

        return $user;
    }

    public static function updateOneSignalPlayerId($id, $one_signal_player_id) {
        $user = UserRepository::find($id);
        $user->one_signal_player_id = $one_signal_player_id;
        $user->save();
        return $user;
    }

}
