<?php

namespace App\Console\Commands;

use App\SubscriptionBundleType;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Mtc\Shop\Assessment\Assessment;
use Mtc\Shop\Order;
use MtcPharmacy\Subscriptions\Classes\Subscription;
use MtcPharmacy\Subscriptions\Classes\SubscriptionItem;
use MtcPharmacy\Subscriptions\Classes\SubscriptionPreference;

/**
 * Examples:
 *     php artisan subscriptions:generate_from_orders
 */

class GenerateSubscriptionsCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'subscriptions:generate_from_orders';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate subscription from paid orders that include items which have requested this service.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $order_ids = $this->get_orders_to_process();
        $this->info('Found the following orders to process: '.$order_ids->toJson());

        foreach ($order_ids as $order_id) {
            $this->info("Processing order id:{$order_id}");

            $order = Order::find($order_id);

            $order_items_grouped = $this->get_order_items_grouped($order);

            $this->info('* Unbundled items:');
            foreach ($order_items_grouped['unbundled'] as $order_item) {
                $this->info(" - order item id:{$order_item->id}");
                if ($order_item->has_requested_subscription) {
                    $sub = $this->create_new_subscription($order);
                    $this->add_item_to_subscription($order_item, $sub);
                    $sub->orders()->attach($order);
                    $this->adjust_subscription_interval($sub, $order_item);
                    $this->adjust_subscription_expiry_date($sub, $order_item);
                }
            }

            $this->info('* Bundled items:');
            foreach ($order_items_grouped['bundled'] as $bundle_id => $bundle_items) {
                $this->info(" - bundle id:{$bundle_id}");

                $sub = $this->create_new_subscription($order);
                foreach ($bundle_items as $bundle_item) {
                    $this->add_item_to_subscription($bundle_item, $sub);
                }
                $sub->orders()->attach($order);
                SubscriptionBundleType::relate($sub, $bundle_item->bundle->type);
                $this->adjust_subscription_interval($sub, $order_item);
                $this->adjust_subscription_expiry_date($sub, $order_item);
            }
        }

        $this->info('Done.');
    }

    /** * HELPERS ** */

    private function get_orders_to_process()
    {
        $query_builder = DB::table('order_items AS oi')
            ->selectRaw('DISTINCT oi.order_id')
            ->join('order AS o', 'o.id', '=', 'oi.order_id')
            ->leftJoin('subscriptions_orders AS so', 'so.order_id', '=', 'oi.order_id')
            ->where('o.paid', 1)
            ->where('oi.has_requested_subscription', 1)
            ->whereNull('so.id');

        return $query_builder->pluck('order_id');
    }

    private function add_item_to_subscription($container_item, $sub)
    {
        $si = SubscriptionItem::createFromShopItem($container_item->item, $container_item->item_size);
        $si->subscription()->associate($sub);
        $si->save();

        $shop_item_size_id = $container_item->item_size->id ?? '-';
        $this->info(" --- added shop item id:{$container_item->item->id}|{$shop_item_size_id}");
    }

    private function create_new_subscription($order)
    {
        $sub = new Subscription;
        $sub->status = Subscription::STATUS_ACTIVE;
        $sub->member()->associate($order->member);
        $sub->save();
        $this->info(" -- created subscripton id:{$sub->id}");

        return $sub;
    }

    private function get_order_items_grouped($order)
    {
        $order_items_grouped = [
            'bundled' => [],
            'unbundled' => [],
        ];

        foreach ($order->items as $order_item) {
            if ($order_item->bundle) {
                if (! isset($order_items_grouped['bundled'][$order_item->bundle->id])) {
                    $order_items_grouped['bundled'][$order_item->bundle->id] = [];
                }
                $order_items_grouped['bundled'][$order_item->bundle->id][] = $order_item;
            } else {
                $order_items_grouped['unbundled'][] = $order_item;
            }
        }

        return $order_items_grouped;
    }

    private function adjust_subscription_interval($subscription, $order_item)
    {
        $sub_config = SubscriptionPreference::init($order_item->item->id, $order_item->item_size->id ?? null);

        if ($sub_config) {
            $subscription->interval = $sub_config->interval;
            $subscription->interval_multiplier = $sub_config->interval_multiplier;
            $subscription->save();
        }
    }

    private function adjust_subscription_expiry_date($subscription, $order_item)
    {
        $assessment = Assessment::getCompletedForItem($order_item->item);
        if ($assessment) {
            $subscription->expiry_date = $assessment->getExpiryDate();
        } else {
            $subscription->expiry_date = date('Y-m-d', strtotime('+10 years'));
        }

        $subscription->save();
    }
}
