<?php

namespace App\Http\Controllers\api;

use Exception;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Http\Requests\ScreenRequest;
use App\Models\Administration\Screen;
use App\Models\Administration\RoleScreen;

class ScreenController extends Controller
{
    protected $MESSAGES = [
        'INDEX' => 'WARNING.SCREEN_INDEX',
        'SCREEN_PARENT' => 'WARNING.SCREEN_PARENT',
        'DUPLICATED' => 'WARNING.SCREEN_DUPLICATED',
        'SORT_ORDER' => 'WARNING.SORT_ORDER',
        'STORE' => 'WARNING.SCREEN_STORE',
        'NOT-FOUND' => 'SCREEN.NOT_FOUND',
        'UPDATE' => 'WARNING.SCREEN_UPDATE',
        'AVAILABLE' => 'WARNING.SCREEN_AVAILABLE',
        'NOT_PERMISSION' => 'WARNING.NOT_PERMISSION',
        'VISIBLE' => 'WARNING.SCREEN_VISIBLE',
        'DESTROY' => 'WARNING.SCREEN_DESTROY',
        'USER_MENU' => 'WARNING.USER_MENU',
        'HAS_PERMISSION' => 'WARNING.HAS_PERMISSION',
    ];

    public function __construct()
    {
        $this->CHANNEL = 'screen_errors';
    }

    public function index(ScreenRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator();

            $screens_query = Screen::with(['parent', 'user_creator', 'user_updater'])
                ->when(!$isSystemAdministrator, function ($query) {
                    $query->where([
                        ['visible', true]
                    ]);
                })->where([
                    ['is_active', !$this->hasSpecial($request->fk_office)]
                ])->orderBy('id', 'ASC');

            $screens = $screens_query->get();

            if (!$isSystemAdministrator) {
                $this->makeFieldHidden($screens, ['visible']);
            }

            return $this->responseJson(null, $screens, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['INDEX'], null, 501);
        }
    }


    public function getParent(ScreenRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator();

            $screens_query = Screen::select('id', 'screenname', 'icon')->whereNull('fk_parent')
                ->where([
                    ['available', true],
                    ['is_active', !$this->hasSpecial($request->fk_office)]
                ])
                ->when(!$isSystemAdministrator, function ($query) use ($request) {
                    $query->where([
                        ['visible', true],
                    ]);
                })->orderBy('sortorder');

            $screens = $screens_query->get();

            if (!$isSystemAdministrator) {
                $screens->makeHidden('visible');
            }

            return $this->responseJson(null, $screens, 200);
        } catch (Exception $ex) {
            $this->generateLog('screens.errors', $ex);
            return $this->responseJson($this->MESSAGES['SCREEN_PARENT'], null, 501);
        }
    }


    public function store(ScreenRequest $request)
    {
        try {
            if (Screen::where('is_active', true)->where(function ($query) use ($request) {
                $query->where(function ($query) use ($request) {
                    $query->where([
                        ['screenname', trim(mb_strtoupper($request->screenname, 'UTF-8'))]
                    ])->orWhere([
                        ['url', trim(mb_strtolower($request->url, 'UTF-8'))]
                    ]);
                })->whereNot([
                    ['url', '#']
                ]);
            })->exists()) {
                return $this->responseJson($this->MESSAGES['DUPLICATED'], null, 501);
            }

            if (Screen::where([
                ['fk_parent', $request->fk_parent],
                ['sortorder', $request->sortorder],
                ['is_active', true]
            ])->exists()) {
                return $this->responseJson($this->MESSAGES['SORT_ORDER'], null, 501);
            }

            Screen::create([
                'screenname' => trim(mb_strtoupper($request->screenname, 'UTF-8')),
                'url' => trim(mb_strtolower($request->url, 'UTF-8')),
                'icon' => trim(mb_strtolower($request->icon, 'UTF-8')),
                'fk_parent' => !isset($request->fk_parent) || $request->fk_parent == 0 ? null : $request->fk_parent,
                'sortorder' => $request->sortorder,
                'fk_usercreator' => $this->user()->id
            ]);

            return $this->responseJson(null, true, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['STORE'], null, 501);
        }
    }

    public function update(ScreenRequest $request)
    {
        try {
            $screen = Screen::find($request->id);

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

            if (Screen::where([
                ['id', '<>', $screen->id],
                ['is_active', true]
            ])->where(function ($query) use ($request) {
                $query->where([
                    ['screenname', trim(mb_strtoupper($request->screenname, 'UTF-8'))]
                ])->orWhere([
                    ['url', trim(mb_strtolower($request->url, 'UTF-8'))]
                ])->whereNot([
                    ['url', '#']
                ]);
            })->exists()) {
                return $this->responseJson($this->MESSAGES['DUPLICATED'], null, 501);
            }

            if (Screen::where([
                ['id', '<>', $screen->id],
                ['fk_parent', $screen->fk_parent],
                ['is_active', true]
            ])->where(function ($query) use ($request) {
                $query->where([
                    ['sortorder', $request->sortorder]
                ]);
            })->exists()) {
                return $this->responseJson($this->MESSAGES['SORT_ORDER'], null, 501);
            }

            $screen->screenname = trim(mb_strtoupper($request->screenname, 'UTF-8'));
            $screen->url = trim(mb_strtolower($request->url, 'UTF-8'));
            $screen->icon = trim(mb_strtolower($request->icon, 'UTF-8'));
            $screen->fk_parent = !isset($request->fk_parent) || $request->fk_parent == 0 ? null : $request->fk_parent;
            $screen->sortorder = $request->sortorder;
            $screen->fk_userupdater = $this->user()->id;

            $screen->update();

            return $this->responseJson(null, true, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['UP'], null, 501);
        }
    }

    public function updateStatus(ScreenRequest $request)
    {
        try {
            $screen = Screen::find($request->id);

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

            $screen->available = $request->available;
            $screen->fk_userupdater = $this->user()->id;

            $screen->update();

            return $this->responseJson(null, true, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['AVAILABLE'], null, 501);
        }
    }

    public function updateVisibility(ScreenRequest $request)
    {
        try {
            $screen = Screen::find($request->id);

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

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

            $screen->update([
                'visible' => $request->visible,
                'fk_userupdater' => $this->user()->id,
            ]);


            $screen->update();

            return $this->responseJson(null, true, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['VISIBLE'], null, 501);
        }
    }

    public function destroy(ScreenRequest $request)
    {
        try {
            $screen = Screen::findOrFail($request->id);

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

            $screen->is_active = $this->hasSpecial($request->fk_office);
            $screen->fk_userupdater = $this->user()->id;
            $screen->update();

            return $this->responseJson(null, true, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['DESTROY'], null, 501);
        }
    }

    public function getUserMenu(ScreenRequest $request)
    {
        try {
            if ($this->hasSystemAdministrator()) {
                $screens = Screen::select(
                    'id',
                    'screenname as label',
                    'icon as icon'
                )->with(['items' => function ($query) {
                    $query->select(
                        'screenname as label',
                        DB::raw('CONCAT("/", url) as route'),
                        'icon as icon',
                        'fk_parent'
                    )
                        ->orderBy('sortorder');
                }])->whereNull('fk_parent')->where('is_active', true)
                    ->orderBy('sortorder')
                    ->get();

                $screens->makeHidden('id');
            } else {
                $user_role = $this->user_role($request->fk_office);

                $screens = Screen::select(
                    'sc_screens.id',
                    'screenname as label',
                    'icon as icon'
                )->join('sc_role_screens as rs', 'rs.fk_screen', 'sc_screens.id')
                    ->where([
                        ['sc_screens.available', true],
                        ['sc_screens.visible', true],
                        ['sc_screens.is_active', true],
                        ['rs.is_active', true],
                        ['rs.fk_role', $user_role->id]
                    ])->whereNull('fk_parent')->with(['items' => function ($query) use ($user_role) {
                        $query->select(
                            'screenname as label',
                            DB::raw('CONCAT("/", url) as route'),
                            'icon as icon',
                            'fk_parent'
                        )->join('sc_role_screens as rs', 'rs.fk_screen', 'sc_screens.id')->where([
                            ['sc_screens.available', true],
                            ['sc_screens.visible', true],
                            ['sc_screens.is_active', true],
                            ['rs.is_active', true],
                            ['rs.fk_role', $user_role->id]
                        ])->orderBy('sortorder');
                    }])->orderby('sortorder')->get();

                $screens->makeHidden('id');
            }

            return $this->responseJson(null, $screens, 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['USER_MENU'], null, 501);
        }
    }

    public function hasPermission(ScreenRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator();

            if ($isSystemAdministrator) {
                return $this->responseJson(null, true, 200);
            }

            $user_role = $this->user_role($request->fk_office);

            $permission = RoleScreen::where([
                ['fk_role', $user_role->id],
                ['is_active', true]
            ])->whereHas('screen', function ($query) use ($request) {
                $query->where([
                    ['screenname', trim(mb_strtoupper($request->screenname, $this->UTF_ENCODING))],
                    ['available', true],
                    ['visible', true],
                    ['is_active', true]
                ]);
            });

            return $this->responseJson(null, $permission->exists(), 200);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['HAS_PERMISSION'], null, 501);
        }
    }
}
