<?php

namespace App\Repositories\Business;

use App\Modules\Enums\PlatformType;
use App\Common\Alipay;
use App\Common\Qiniu;
use App\Common\Sms;
use App\Modules\Enums\AlipayLoginType;
use App\Modules\Enums\ErrorCode;
use App\Modules\Enums\LoginType;
use App\Modules\Enums\SmsType;
use App\Exceptions\Api\ApiException;
use App\Modules\Models\Customer\Customer;
use App\Modules\Repositories\BaseRepository;
use App\Modules\Repositories\Business\BaseBusinessRepository;
use App\Util\AuthUtil;
use App\Util\CustomerUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;

/**
 * Class EloquentHistoryRepository.
 */
class BusinessRepository extends BaseBusinessRepository
{
    /**
     * @return string
     */
    private function guardStr()
    {
        return "business";
    }

    /**
     * @param $credentials
     * @return \Illuminate\Http\JsonResponse
     * @throws ApiException
     */
    public function login($credentials)
    {
        try {
            // attempt to verify the credentials and create a token for the user
            if (!$token = Auth::guard($this->guardStr())->attempt($credentials)) {
                throw new ApiException(ErrorCode::LOGIN_FAILED, trans('api.error.login_failed'));
            }
        } catch (JWTException $e) {
            // something went wrong whilst attempting to encode the token
            throw new ApiException(ErrorCode::CREATE_TOKEN, trans('api.error.create_token_failed'));
        }

        $user = Auth::guard($this->guardStr())->User();
        $user->last_login_at = Carbon::now();
        $user->save();

        $expire = Auth::setToken($token)->getPayload()->get('exp');
        $token = 'Bearer ' . $token;

        $customer_id = $user->id;
        // all good so return the token
        return compact('token', 'expire','customer_id');
    }

    /**
     * @return array
     * @throws ApiException
     */
    public function refreshToken()
    {
        try {
            $old_token = Auth::getToken();
            $token = Auth::refresh($old_token);
        } catch (TokenExpiredException $e) {
            throw new ApiException(ErrorCode::TOKEN_EXPIRE, trans("api.error.token_expire"), array());
        } catch (JWTException $e) {
            throw new ApiException(ErrorCode::TOKEN_INVALID, trans("api.error.token_invalid"), array());
        }

        $expire = Auth::setToken($token)->getPayload()->get('exp');
        $token = 'Bearer ' . $token;

        // all good so return the token
        return compact('token', 'expire');
    }

    /**
     * @return array
     * @throws ApiException
     */
    private function checkTokenInternal()
    {
        $isValid = true;
        try {
            $token = Auth::getToken();
            AuthUtil::checkOrFail($this->guardStr());
        } catch (TokenExpiredException $e) {
            $isValid = false;
            try {
                $token = Auth::refresh();
                Auth::setToken($token);
                AuthUtil::checkOrFail($this->guardStr());
            } catch (TokenExpiredException $e) {
                throw new ApiException(ErrorCode::TOKEN_EXPIRE, trans("api.error.token_expire"), array());
            } catch (JWTException $e) {
                throw new ApiException(ErrorCode::TOKEN_INVALID, trans("api.error.token_invalid"), array());
            }
        } catch (JWTException $e) {
            throw new ApiException(ErrorCode::TOKEN_INVALID, trans("api.error.token_invalid"), array());
        }

        $expire = Auth::setToken($token)->getPayload()->get('exp');
        $token = 'Bearer ' . $token;

        // all good so return the token
        return $isValid ? array() : compact('token', 'expire');
    }


    /**
     * @return array
     */
    public function checkToken()
    {
        $ret = $this->checkTokenInternal();

        $user = Auth::User();
        $user->last_login_at = Carbon::now();
        $user->save();

        return $ret;
    }

    /**
     * @return mixed
     */
    public function logout()
    {
        Auth::invalidate();
        return true;
    }

    /**
     * @param $input
     * @throws ApiException
     * @return boolean
     */
    public function sms($input)
    {
        $type = $input['type'];
        $telephone = $input['telephone'];

        switch ($type) {
            //register case
            case SmsType::REGISTER:
                if (CustomerUtil::telephoneExist($telephone)) {
                    throw new ApiException(ErrorCode::USER_ALREADY_EXIST, trans('api.error.user_already_exist'));
                }
                break;
            //reset password case
            case SmsType::RESET_PASSWORD:
                if (!CustomerUtil::telephoneExist($telephone)) {
                    throw new ApiException(ErrorCode::USER_NOT_EXIST, trans('api.error.user_not_exist'));
                }
                break;
            case SmsType::SMS_LOGIN:
                if (!CustomerUtil::telephoneExist($telephone)) {
                    $customer = $this->create(array('telephone' => $telephone));
                }
                break;
            case SmsType::BIND:
                if (CustomerUtil::telephoneExist($telephone)) {
                    throw new ApiException(ErrorCode::USER_ALREADY_EXIST, trans('api.error.user_already_exist'));
                }
                break;
            default:
                throw new ApiException(ErrorCode::SMS_INVALID_TYPE, trans('api.error.sms_invalid_type'));
                break;
        }

        $result = Sms::sendCode($telephone);

        if (!$result) {
            throw new ApiException(ErrorCode::SMS_ERROR, trans('api.error.sms_error'));
        }

        return true;
    }

    /**
     * @param Customer $customer
     * @return string
     */
    public function headImageUploadToken(Customer $customer)
    {
        $policy = array(
            'callbackUrl' => config("constants.qiniu.callback_base_url") . '/customers/headerUpdateCallback',
            'callbackBody' => 'fkey=$(key)&userId=' . $customer->id
        );

        return Qiniu::getUpToken(config('constants.qiniu.user_bucket'), 'png', $policy);
    }

    /**
     * @param $customer_id
     * @param $price
     * @return mixed
     */
    public function updateCustomerAccount($customer_id, $price)
    {
        $customer = Customer::find($customer_id);
        $customer->balance = $customer->balance - $price;
        $customer->save();
    }

}
