<?php

namespace Mtc\Plugins\NHS\Classes;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Validator;
use Mtc\Modules\Members\Models\Member;

class PrescriptionItem extends Model
{
    /**
     * The table associated with the model.
     */
    protected $table = 'nhs_prescription_items';

    /**
     * Average Number of days for the medication to be delivered to the customer
     */
    const DAYS_TO_SHIP = 7;

    /**
     * Number of days that the customer should reorder their medication before it runs out.
     */
    const DAYS_TO_REORDER_BEFORE_COMPLETION_DATE = 9;

    protected $fillable = [
        'name',
        'quantity',
        'refill_date',
        'refill_date_new',
        'one_off_prescription',
        'frequency_days',
        'nhs_unilexicon_product_id',
    ];

    protected $hidden = [];

    protected $casts = [
        'one_off_prescription' => 'integer',
        'nhs_unilexicon_product_id' => 'string',
    ];

    private $rules = [
        'name' => 'required',
        'quantity' => 'required | integer | min:1',
        'refill_date' => 'nullable | date',
        'one_off_prescription',
        'additional_info',
        'frequency_days' => 'nullable | integer',
    ];

    public function validate()
    {
        return Validator::make($this->attributes, $this->rules);
    }

    public function prescription()
    {
        return $this->belongsTo(Prescription::class);
    }

    public function unilexiconProduct()
    {
        return $this->belongsTo(NHSUnilexiconProduct::class, 'nhs_unilexicon_product_id', 'id');
    }

    /**
     * Gets a refill date of member's NHS prescription
     *
     * @param $item
     * @param Member $member
     * @return false|string
     */
    public static function getRefillDate($item, Member $member)
    {
        // Find out how many days does the member have of this medication left, if no date specified for the current medication
        $refill_after_days = self::getMedicationDaysRemaining($item, $member);

        // As the medication is started next day after it ends, add one day
        $refill_after_days++;

        // If there's less days of medication available than days to ship, we set days to ship as the base
        $refill_after_days = max(self::DAYS_TO_SHIP, $refill_after_days);

        $refill_after_days += self::daysMedicationLasts($item);

        // Return the refill date
        return (new Carbon)
            ->addDays($refill_after_days)
            ->format('Y-m-d');
    }

    /**
     * Calculates the number of days the medication lasts, depending on pack size, dose and quantity per dose
     *
     * @param $item
     * @return float|int
     */
    public static function daysMedicationLasts($item)
    {
        // Now calculate the number of days the selected medication would last and add that to the medication days left
        $dosage = Dosage::query()->find($item['dosage_id']);
        if (
            (float) $dosage->quantity_per_day > 0
            && (float) $item['quantity_per_dose'] > 0
            && (float) $item['quantity'] > 0
        ) {
            return floor(($item['quantity'] / (float) $item['quantity_per_dose']) / (float) $dosage->quantity_per_day);
        }

        return 0;
    }

    /**
     * Gets the number of days that are remaining of this medication based on order history.
     *
     * @param array $item
     * @param Member $member
     * @return int
     */
    public static function getMedicationDaysRemaining($item, Member $member)
    {
        if (! empty($item['refill_date'])) {
            if ($item['refill_date'] < (new Carbon)->format('Y-m-d')) {
                return 0;
            }

            // Add +1 to the date diff. E.g., if medication ends tomorrow, it's still 2 days left.
            return new Carbon($item['refill_date'])->diffInDays(Carbon::now()) + 1;
        }
        if ($nhs_order_item = self::getLastPrescriptionOrdered($item['name'], $member)) {
            $refill_date_time = new Carbon($nhs_order_item->reminder_date)->format('Y-m-d');
            if ($refill_date_time > (new Carbon)->format('Y-m-d')) {
                // Add +1 to the date diff. E.g., if medication ends tomorrow, it's still 2 days left.
                return new Carbon($refill_date_time)->diffInDays(Carbon::now()) + 1;
            }

            return 0;
        }

        return 0;
    }

    /**
     * @param $item_name
     * @param Member $member
     * @return Model|null|static
     */
    public static function getLastPrescriptionOrdered($item_name, Member $member)
    {
        return \Mtc\Shop\Order\Item::query()
            ->join('order', function ($join) use ($member): void {
                $join
                    ->on('order.id', '=', 'order_items.order_id')
                    ->where('order.member', '=', $member->id)
                    ->where('order.paid', '=', '1');
            })
            ->where('order_items.item_name', 'LIKE', $item_name.'%')
            ->where('order_items.nhs_prescription', '1')
            ->orderBy('reminder_date', 'DESC')
            ->first();
    }

    /**
     * Gets the reorder date. Return today if calculates past date.
     *
     * @param string $refill_date
     * @return string
     */
    public static function getReorderDate($refill_date)
    {
        return Carbon::createFromFormat('Y-m-d', $refill_date)
            ->subDays(self::DAYS_TO_REORDER_BEFORE_COMPLETION_DATE)
            ->format('Y-m-d');
    }

    public function get_price()
    {
        $price = 0;

        $multiplier = (int) ($this->unilexiconProduct->number_of_charges ?? 1);
        $price *= $multiplier;
        $price = round($price, 2);

        return $price;
    }

    public function get_payable_price()
    {
        if ($this->prescription->nhs_member->is_pay_for_prescriptions) {
            return $this->get_price();
        } else {
            return 0;
        }
    }
}
