<?php namespace App\Http\Controllers\Frontend;

use App\Http\Controllers\Controller;
use Facades\ModalHelpers\DeviceModalHelper;
use Facades\Repositories\DeviceGroupRepo;
use Facades\Repositories\SmsEventQueueRepo;
use Facades\Repositories\UserDriverRepo;
use Facades\Repositories\UserRepo;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Hash;
use Tobuli\Exceptions\ValidationException;
use Formatter;
use Validator;

class ApiController extends Controller
{
    public function login()
    {
        $validator = Validator::make(request()->all(), [
            'email' => 'required',
            'password' => 'required',
        ]);

        if ($validator->fails())
            return response()->json(['status' => 0, 'errors' => $validator->errors()], 422);

        if (isPublic()) {
            if ($user = \Facades\RemoteUser::getByCredencials($this->data['email'], $this->data['password'])) {
                return [
                    'status' => 1,
                    'user_api_hash' => $user->api_hash,
                    'permissions' => $user->getPermissions(),
                ];
            }
        } else {
            if (Auth::attempt(['email' => $this->data['email'], 'password' => $this->data['password']])) {

                if ( ! Auth::User()->active)
                {
                    Auth::logout();
                    return response()->json(['status' => 0, 'message' => trans('front.login_suspended')], 401);
                }

                if (Auth::User()->isExpired())
                {
                    Auth::logout();
                    return response()->json(['status' => 0, 'message' => trans('front.subscription_expired')], 401);
                }

                if (empty(Auth::User()->api_hash)) {
                    while (!empty(UserRepo::findWhere(['api_hash' => $hash = Hash::make(Auth::User()->email . ':' . $this->data['password'])]))) ;
                    Auth::User()->api_hash = $hash;
                    Auth::User()->save();
                }

                return [
                    'status'        => 1,
                    'user_api_hash' => Auth::User()->api_hash,
                    'permissions'   => Auth::User()->getPermissions()
                ];
            }
        }

        return response()->json(['status' => 0, 'message' => trans('front.login_failed')], 401);
    }

    public function getSmsEvents()
    {
        UserRepo::updateWhere(['id' => $this->user->id], ['sms_gateway_app_date' => date('Y-m-d H:i:s')]);
        $items = SmsEventQueueRepo::getWhereSelect(['user_id' => $this->user->id], ['id', 'phone', 'message'], 'created_at')->toArray();


        if (!empty($items))
            SmsEventQueueRepo::deleteWhereIn(array_pluck($items, 'id'));

        return [
            'status' => 1,
            'items' => $items
        ];
    }

    #
    # Devices
    #

    public function getDevices(\ModalHelpers\DeviceModalHelper $deviceModalHelper)
    {
        $grouped = [];

        if ($this->user->perm('devices', 'view')) {

            $devices = UserRepo::getDevicesWith($this->user->id, [
                'devices',
                'devices.sensors',
                'devices.services',
                'devices.driver',
                'devices.traccar',
                'devices.icon',
                'devices.users'
            ]);

            $device_groups = ['0' => trans('front.ungrouped')] + DeviceGroupRepo::getWhere(['user_id' => $this->user->id])->lists('title', 'id')->all();

            $grouped = [];

            foreach ($devices as $device) {
                $group_id = empty($device->pivot->group_id) ? 0 : $device->pivot->group_id;
                $group_id = empty($device_groups[$group_id]) ? 0 : $group_id;

                if (!isset($grouped[$group_id])) {
                    $grouped[$group_id] = [
                        'id'    => $group_id,
                        'title' => $device_groups[$group_id],
                        'items' => []
                    ];
                }

                $grouped[$group_id]['items'][] = $deviceModalHelper->generateJson($device, FALSE, TRUE);
            }

            unset($devices);

            $grouped = array_values($grouped);
        }

        return $grouped;
    }

    public function getDevicesJson()
    {
        $data = DeviceModalHelper::itemsJson();

        return $data;
    }

    public function getUserData()
    {
        $dStart = new \DateTime(date('Y-m-d H:i:s'));
        $dEnd = new \DateTime($this->user->subscription_expiration);
        $dDiff = $dStart->diff($dEnd);
        $days_left = $dDiff->days;

        $plan = Config::get('tobuli.plans.' . $this->user->devices_limit);
        if (empty($plan)) {
            $plan = isset($this->user->billing_plan->title) ? $this->user->billing_plan->title : NULL;
            if (empty($plan))
                $plan = trans('admin.group_' . $this->user->group_id);
        }

        return [
            'email' => $this->user->email,
            'expiration_date' => $this->user->subscription_expiration != '0000-00-00 00:00:00'
                ? Formatter::time()->human($this->user->subscription_expiration)
                : NULL,
            'days_left' => $this->user->subscription_expiration != '0000-00-00 00:00:00' ? $days_left : NULL,
            'plan' => $plan,
            'devices_limit' => intval($this->user->devices_limit),
            'group_id' => $this->user->group_id
        ];
    }

    public function setDeviceExpiration()
    {
        if (!isAdmin())
            return response()->json(['status' => 0, 'error' => trans('front.dont_have_permission')], 403);

        $validator = Validator::make(request()->all(), [
            'imei' => 'required',
            'expiration_date' => 'required|date',
        ]);

        if ($validator->fails())
            return response()->json(['status' => 0, 'errors' => $validator->errors()], 400);

        $device = \Tobuli\Entities\Device::where('imei', request()->get('imei'))->first();

        if (!$device)
            return response()->json(['status' => 0, 'errors' => ['imei' => dontExist('global.device')]], 400);

        $device->expiration_date = request()->get('expiration_date');
        $device->save();

        return response()->json(['status' => 1], 200);
    }

    public function enableDeviceActive()
    {
        $validator = Validator::make(request()->all(), ['id' => 'required']);

        if ($validator->fails())
            throw new ValidationException($validator->errors());

        $device = \Tobuli\Entities\Device::find(request('id'));

        $this->checkException('devices', 'enable', $device);

        if (!$device->active)
            $device->update(['active' => true]);

        return response()->json(['status' => 1], 200);
    }

    public function disableDeviceActive()
    {
        $validator = Validator::make(request()->all(), ['id' => 'required']);

        if ($validator->fails())
            throw new ValidationException($validator->errors());

        $device = \Tobuli\Entities\Device::find(request('id'));

        $this->checkException('devices', 'disable', $device);

        if ($device->active)
            $device->update(['active' => false]);

        return response()->json(['status' => 1], 200);
    }

    public function geoAddress()
    {
        if (empty($this->data['lat']) || empty($this->data['lon']))
            return '-';

        return getGeoAddress($this->data['lat'], $this->data['lon']);
    }

    public function setFcmToken()
    {
        $validator = Validator::make(request()->all(), ['token' => 'required']);

        if ($validator->fails())
            throw new ValidationException($validator->errors());

        $token = $this->user->fcm_tokens()->firstOrNew([
            'token' => $this->data['token']
        ]);
        $token->save();

        return response()->json(['status' => 1], 200);
    }

    public function getServicesKeys()
    {
        $services = [];

        $services['maps']['google']['key'] = settings('main_settings.google_maps_key');

        return response()->json(['status' => 1, 'items' => $services], 200);
    }

    public function __call($name, $arguments)
    {
        list($class, $method) = explode('#', $name);

        try {
            $class = App::make("App\Http\Controllers\Frontend\\" . $class);
            $response = App::call([$class, $method]);
        } catch (\ReflectionException $e) {
            return response()->json(['status' => 0, 'message' => 'Method does not exist!'], 500);
        }

        if ( ! is_array($response))
            return $response;

        if (!array_key_exists('status', $response))
            $response['status'] = 1;

        $status_code = 200;
        if ($response['status'] == 0)
            $status_code = 400;

        if (array_key_exists('perm', $response))
            $status_code = 403;

        return response()->json($response, $status_code);
    }
}