<?php


namespace App\Repositories;


use App\Notifications\SubscriptionRenewedNotification;
use App\PaymentType;
use App\Plan;
use App\Subscription;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class SubscriptionRepository {
    public static function all() {
        return Subscription::all();
    }

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

    public static function create(array $data) {
        return Subscription::create($data);
    }

    public static function update(array $data, $id) {
        Subscription::findOrFail($id)->update($data);
        return Subscription::findOrFail($id);
    }

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

    public static function subscribe(string $company_id, string $plan_id, bool $set_date_after_current_subscription = false) {
        //0. Check if current subscription is the same
        $company = CompanyRepository::find($company_id);
        if($company->active_plan!=null && $company->active_plan->plan_id == $plan_id)
            throw new \Exception("Si te quieres suscribir a una nueva tarifa, ésta debe ser distinta a la que estás actualmente.");

        //1. Obtenim parametres
        $params = [
            "company_id" => $company_id,
            "plan_id" => $plan_id
        ];
        if($set_date_after_current_subscription && $company->active_plan!=null && $company->active_plan->end_date!=null) {
            $params["start_date"] = $company->active_plan->end_date->copy()->addDay()->startOfDay(); //setejem data d'inici
        }

        //2. Creem
        $sub = SubscriptionRepository::create($params);

        //3. Generar company order
        $pla = Plan::findOrFail($plan_id);

        $order = CompanyOrderRepository::create([
            "company_id" => $company_id,
            "subscription_id" => $sub->id,
            "subtotal" => $pla->subtotal,
            "vat" => $pla->tax_amount,
            "total" => $pla->total
        ]);

        $sub->refresh();

        return $sub;
    }

    /**
     * @param $id
     * @param bool $override
     * @param bool $fromWebhook - Serveix per indicar si la crida prove de webhook o no. Si es true, no parlara amb
     *                              Stripe perque significa que ja ha estat cobrat
     * @return mixed
     * @throws \Exception
     */
    public static function pay($id, bool $override = false, bool $fromWebhook = false) {
        //0. Fetch
        $sub = SubscriptionRepository::find($id);
        $company = $sub->company;
        $orderToPay = SubscriptionRepository::getOrderToPay($id);
        if(!$orderToPay) throw new \Exception("We haven't found any order to pay");
        if($company->active_plan && $company->active_plan->id == $id && !$fromWebhook){
            //Estem intentant renovar la suscripcio actual, mentre aixo ho fa stripe
            throw new \Exception("You're renewing the current subscription. Stripe will do it automatically.");
        }

        DB::beginTransaction();
        try {
            //1. gestionar subscripcio amb stripe
            if(!$fromWebhook) StripeRepository::payCompanySubscription($company,$sub,$override);

            //2. modificar dates i gestionar override
            if($override && $sub->company->active_plan!=null) {
                $active_plan = $sub->company->active_plan;
                $active_plan->end_date = Carbon::now()->addDays(-1); //Forcem la finalització de l'actual
                $active_plan->save();
                $sub->start_date = Carbon::now(); //Aquesta passa a ser l'actual
            }
            else {
                //la subscripció actual la deixem normal
                $sub->start_date = ($sub->start_date && $sub->start_date > Carbon::now()) ?  $sub->start_date  :  Carbon::now(); //Si ja ha estat establert amb anterioritat, el respectem, sempre i quan ja hagi passat la data
            }
            $sub->end_date = $sub->start_date->addMonth();
            $sub->save();

            //3. marcar pagament com a pagat
            PaymentRepository::pay($orderToPay->payment_id, PaymentType::where("slug", "stripe")->first()->id);

            DB::commit();
        }
        catch(\Exception $e) {
            DB::rollBack();
            throw $e;
        }

        //3. notificar
        $sub->refresh();
        $orderToPay = CompanyOrderRepository::find($orderToPay->id);
        $company = $sub->company;
        $payment = $orderToPay->payment;
        $invoice = $orderToPay->invoice;
        $company->notify((new SubscriptionRenewedNotification($company, $sub, $invoice, $payment)));

        return $sub;
    }

    public static function getOrderToPay($id) {
        return DB::table("subscriptions as s")
            ->select("co.*")
            ->leftJoin("company_orders as co", "s.id", "co.subscription_id")
            ->leftJoin("payments as p", "p.id", "co.payment_id")
            ->where([
                ["s.id", $id],
                ["p.charged", false]
            ])
            ->orderByDesc("created_at")
            ->first();
    }

    public static function cancel($id) {
        SubscriptionRepository::find($id)->cancel();
    }
}
