<?php

/**
 * Coupon code Eloquent model
 * @author Uldis Zvirbulis <uldis.zvirbulis@mtcmedia.co.uk>
 * @version 14.03.2017
 *
 */
namespace Mtc\Shop\Coupon;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Mtc\Shop\Coupon;

/**
 * Coupon code Eloquent model.
 * Implements Shop coupon main functionality
 *
 * @version 22/09/16
 * @author Uldis Zvirbulis <uldis.zvirbulis@mtcmedia.co.uk>
 */
class Code extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'coupons_codes';

    /**
     * @var array The attributes that are mass assignable.
     */
    protected $fillable = [
        'coupon_id',
        'code',
        'used',
        'order_id',
    ];

    /**
     * Scope - ofCoupon()
     *
     * @param Builder $query Query to extend
     * @param mixed $coupon reference of coupon (allows int id, array or object)
     * @return Builder
     */
    public function scopeOfCoupon(Builder $query, $coupon)
    {
        return $query->where('coupon_id', id($coupon));
    }

    /**
     * Scope - search()
     * Used for setting search params
     *
     * @param \Illuminate\Database\Eloquent\Builder $query Query builder object
     * @param array $value Array of search params
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeSearch($query, $value)
    {
        if (! empty($value['coupon_id'])) {
            $query = $query->where('coupon_id', '=', $value['coupon_id']);
        }
        if (! empty($value['code'])) {
            $query = $query->where('code', 'LIKE', '%'.trim($value['code']).'%');
        }
        if (! empty($value['status'])) {
            switch ($value['status']) {
                case 'used':
                    $query = $query->where('order_id', '>', '0');
                    break;
                case 'unused':
                    $query = $query->where('order_id', '=', '0');
                    break;
            }
        }

        return $query;
    }

    /**
     * Define Eloquent relationship to coupon class
     * @return BelongsTo
     */
    public function coupon()
    {
        return $this->belongsTo(Coupon::class, 'coupon_id', 'id');
    }

    /**
     * Check if code already exists
     * @param string $code coupon code to check
     * @return bool whether this code already exists
     */
    public static function exists($code)
    {
        return self::where('code', $code)->count() > 0;
    }

    /**
     * @param string $base First part of the code, can be used to identify coupon
     * @param integer $length Length of second part of coupon code
     * @return string
     */
    public static function getUniqueCode($base, $length)
    {
        if ($length <= 0) {
            return '';
        } elseif ($length < 5) {
            // Set minimal code length.
            $length = 5;
        }
        $code_unique = false;
        $attempts = 0;
        $chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';

        while (! $code_unique && $attempts < 1000) {
            $code = '';
            for ($i = 0; $i < $length; $i++) {
                $code .= $chars[mt_rand(0, strlen($chars) - 1)];
            }
            if (! self::exists($base.'-'.$code) && ! Coupon::exists($base.'-'.$code)) {
                $code_unique = true;
            }
            ++$attempts;
        }

        return $code;
    }

    /**
     * Generates bulk coupon codes
     * @param Coupon $coupon
     * @param array $params Any additional parameters
     * @return boolean result
     */
    public static function generateBulk(Coupon $coupon, $params)
    {
        if (! empty($params['number']) && $params['number'] <= 0) {
            return false;
        }
        $code_length = ! empty($params['length']) ? $params['length'] : 6;

        for ($i = 0; $i < $params['number']; $i++) {
            self::create([
                'coupon_id' => $coupon->id,
                'code' => $coupon->code.'-'.self::getUniqueCode($coupon->code, $code_length),
            ]);
        }

        return true;
    }
}
