<?php

namespace App\Http\Controllers\api;

use Exception;
use App\Http\Requests\AuthRequest;
use Tymon\JWTAuth\Facades\JWTAuth;
use App\Models\Administration\Role;
use App\Models\Administration\Site;
use App\Http\Controllers\Controller;
use App\Models\Administration\Office;
use Illuminate\Support\Facades\Log;
use Tymon\JWTAuth\Exceptions\JWTException;

class AuthController extends Controller
{
    protected $MESSAGES = [
        'INVALID_CREDENTIALS' => 'AUTH.INVALID_CREDENTIALS',
        'DISABLED_USER' => 'AUTH.DISABLED_USER',
        'NOT_SITE_ASSIGN' => 'AUTH.NOT_SITE_ASSIGN',
        'ERROR_LOGIN' => 'AUTH.ERROR_LOGIN',
        'LOGOUT_SUCCESS' => 'AUTH.LOGOUT_SUCCESS',
        'ERROR_LOGOUT' => 'AUTH.ERROR_LOGOUT',
        'ERROR_REFRESH_TOKEN' => 'AUTH.ERROR_REFRESH_TOKEN',
        'UNAUTHORIZED' => 'AUTH.UNAUTHORIZED',
        'INVALID_SITE' => 'AUTH.INVALID_SITE',
        'INVALID_OFFICE' => 'AUTH.INVALID_OFFICE',
    ];

    public function login(AuthRequest $request)
    {
        try {
            $credentials = $request->only('username', 'password');
            $credentials['is_active'] = true;
            $claims = [];


            if (!$token = JWTAuth::attempt($credentials)) {
                return $this->responseJson($this->MESSAGES['INVALID_CREDENTIALS'], null, 501);
            }

            $user = JWTAuth::user();

            if (!$user->is_active) {
                return $this->responseJson($this->MESSAGES['INVALID_CREDENTIALS'], null, 501);
            }

            if (!$user->available) {
                return $this->responseJson($this->MESSAGES['DISABLED_USER'], null, 501);
            }

            if (!Role::join('sc_office_users', 'sc_office_users.fk_role', 'sc_roles.id')
                ->where([
                    ['sc_roles.rolename', 'MASTER ADMINISTRATOR'],
                    ['sc_office_users.fk_user', $user->id],
                    ['sc_office_users.is_active', true]
                ])->exists()) {
                $user->sites = Site::select('sy_sites.id as site_id', 'sy_sites.sitename')
                    ->leftJoin('sy_offices', 'sy_offices.fk_site', 'sy_sites.id')
                    ->leftJoin('sc_office_users', 'sc_office_users.fk_office', 'sy_offices.id')
                    ->where([
                        ['sc_office_users.fk_user', $user->id],
                        ['sc_office_users.is_active', true],
                        ['sy_offices.available', true],
                        ['sy_offices.is_active', true],
                        ['sy_sites.available', true],
                        ['sy_sites.is_active', true]
                    ])->distinct()->get();

                foreach ($user->sites as $site) {
                    $site->id = $site->site_id;
                    unset($site->site_id);

                    $site_offices = Role::select('sy_offices.id as office_id', 'sy_offices.officename', 'sc_roles.id as role_id', 'sc_roles.rolename', 'sc_roles.special')
                        ->join('sc_office_users', 'sc_office_users.fk_role', 'sc_roles.id')
                        ->join('sy_offices', 'sy_offices.id', 'sc_office_users.fk_office')
                        ->where([
                            ['sy_offices.fk_site', $site->id],
                            ['sc_office_users.fk_user', $user->id],
                            ['sc_office_users.is_active', true]
                        ])->get();

                    foreach ($site_offices as $office) {
                        $office->id = $office->office_id;
                        unset($office->office_id);
                    }

                    $site->site_offices = $site_offices;
                }


                if (!$user->sites) {
                    return $this->responseJson($this->MESSAGES['NOT_SITE_ASSIGN'], null, 501);
                }

                foreach ($user->sites as $site) {
                    $site_unseted = clone $site;
                    unset($site_unseted->site_offices);
                    
                    if (count($site->site_offices) > 0) {
                        $claims = [
                            'user' => [
                                'username' => $user->username,
                                'default_site' => $site_unseted,
                                'default_office' => $site->site_offices[0],
                                'owner' => $user->site->fk_owner == $user->id
                            ],
                        ];
                        break;
                    }
                }
            } else {
                $user->sites = Site::select('id as id', 'sitename')
                    ->where('is_active', true)
                    ->get();

                if (!$user->sites) {
                    return $this->responseJson($this->MESSAGES['NOT_SITE_ASSIGN'], null, 501);
                }

                foreach ($user->sites as $site) {
                    if (count($site->offices) > 0) {
                        $office = $site->offices->first();
                        $office = $office->only('id', 'officename');

                        $claims = [
                            'user' => [
                                'username' => $user->username,
                                'default_site' => $site->only('id', 'sitename'),
                                'default_office' => $office,
                                'master' => true
                            ],
                        ];
                        break;
                    }
                }
            }

            $token = JWTAuth::claims($claims)->fromUser($user);
            return $this->responseJson(null, ['token' => $token], 200);
        } catch (Exception $ex) {
            $this->generateLog('user_errors', $ex);
            return $this->responseJson($this->MESSAGES['ERROR_LOGIN'], null, 501);
        }
    }

    public function logout()
    {
        try {
            JWTAuth::invalidate(JWTAuth::getToken());
            return $this->responseJson($this->MESSAGES['LOGOUT_SUCCESS'], null, 201);
        } catch (JWTException $ex) {
            $this->generateLog('user_errors', $ex);
            return $this->responseJson($this->MESSAGES['ERROR_LOGOUT'], null, 501);
        }
    }

    public function refreshToken()
    {
        try {
            $token = JWTAuth::parseToken()->refresh();
            return $this->responseJson(null, ['token' => $token], 200);
        } catch (JWTException $ex) {
            $this->generateLog('user_errors', $ex);
            return $this->responseJson($this->MESSAGES['ERROR_REFRESH_TOKEN'], null, 501);
        }
    }

    public function refreshTokenOffice(AuthRequest $request)
    {
        try {
            $currentToken = JWTAuth::getToken();
            $user = JWTAuth::parseToken()->authenticate();

            if (!$user) {
                return $this->responseJson($this->MESSAGES['UNAUTHORIZED'], null, 501);
            }

            $site = Site::select('id', 'sitename')
                ->where('id', $request->fk_site)
                ->where('is_active', true)
                ->first();

            if (!$site) {
                return $this->responseJson($this->MESSAGES['INVALID_SITE'], null, 501);
            }

            $office = Office::select('id', 'officename')
                ->where([
                    ['id', $request->fk_office],
                    ['is_active', true]
                ])->first();

            if (!$office) {
                return $this->responseJson($this->MESSAGES['INVALID_OFFICE'], null, 591);
            }

            if (Role::join('sc_office_users', 'sc_office_users.fk_role', 'sc_roles.id')
                ->where([
                    ['sc_roles.rolename', 'MASTER ADMINISTRATOR'],
                    ['sc_office_users.fk_user', $user->id],
                    ['sc_office_users.is_active', true]
                ])->exists()
            ) {
                $claims = [
                    'user' => [
                        'username' => $user->username,
                        'default_site' => $site,
                        'default_office' => $office,
                        'master' => true
                    ],
                ];
            } else {
                $claims = [
                    'user' => [
                        'username' => $user->username,
                        'default_site' => $site,
                        'default_office' => $office,
                        'owner' => $site->fk_owner == $user->id
                    ],
                ];
            }

            $newToken = JWTAuth::claims($claims)->refresh($currentToken);
            return response()->json($newToken, 200);
        } catch (Exception $ex) {
            $this->generateLog('user_errors', $ex);
            return $this->responseJson($this->MESSAGES['ERROR_REFRESH_TOKEN'], null, 501);
        }
    }
}
