<?php

namespace App\Http\Controllers\api;

use Exception;
use App\Models\Administration\Site;
use App\Http\Requests\OfficeRequest;
use App\Http\Controllers\Controller;
use App\Models\Administration\Office;
use App\Models\Administration\OfficeUser;

class OfficeController extends Controller
{
    protected $MESSAGES = [
        'NOT_FOUND' => 'OFFICE.NOT_FOUND',
        'OFFICE_INDEX' => 'WARNING.OFFICE_INDEX',
        'OFFICE_DUPLICATED' => 'WARNING.OFFICE_DUPLICATED',
        'OFFICE_STORE' => 'WARNING.OFFICE_STORE',
        'OFFICE_UPDATE' => 'WARNING.OFFICE_UPDATE',
        'OFFICE_DESTROY' => 'WARNING.OFFICE_DESTROY',
        'OFFICE_AVAILABLE' => 'WARNING.OFFICE_AVAILABLE',
        'OFFICE_VISIBLE' => 'WARNING.OFFICE_VISIBLE',
        'OFFICE_BY_SITE' => 'WARNING.OFFICE_BY_SITE',
        'OFFICE_SHOW' => 'WARNING.OFFICE_SHOW',
    ];

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

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

            $office_query = Office::with(['site' => function ($sites) use ($request) {
                $sites->select('id', 'sitename');
            }, 'user_creator', 'user_updater'])
                ->when(!$isSystemAdministrator, function ($query) {
                    $officesIds = OfficeUser::where([
                        ['fk_user', $this->user()->id],
                        ['is_active', true]
                    ])->with('office')->get()->pluck('office')->pluck('id');

                    $query->where([
                        ['visible', true]
                    ])->whereIn('id', $officesIds);
                })
                ->where([
                    ['is_active', !$this->hasSpecial($request->fk_office)]
                ])->whereHas('site', function ($query) use ($request) {
                    $query->where([
                        ['is_active', !$this->hasSpecial($request->fk_site)]
                    ]);
                });

            $offices = $office_query->orderBy('id', 'ASC')->get();

            if (!$isSystemAdministrator) {
                $this->makeFieldHidden($offices, ['site', 'visible', 'user_updater', 'user_creator']);
            }

            return $this->responseJson(null, $offices, 200);
        } catch (Exception $ex) {
            $this->generateLog('office_errors', $ex);
            return $this->responseJson($this->MESSAGES['OFFICE_INDEX'], 501);
        }
    }

    public function store(OfficeRequest $request)
    {
        try {
            if (Office::where([
                ['fk_site', $request->fk_site],
                ['officename', trim(mb_strtoupper($request->officename, $this->UTF_ENCODING))],
                ['is_active', true]
            ])->exists()) {
                return $this->responseJson($this->MESSAGES['OFFICE_DUPLICATED'], null, 501);
            }

            Office::create([
                'fk_site' => $request->fk_site,
                'officename' => trim(mb_strtoupper($request->officename, $this->UTF_ENCODING)),
                'fk_usercreator' => $this->user()->id,
            ]);

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

    public function update(OfficeRequest $request)
    {
        try {
            $office = Office::find($request->id);

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

            if (Office::where('id', '<>', $office->id)->where(function ($query) use ($request) {
                $query->where([
                    ['fk_site', $request->fk_site],
                    ['officename', trim(mb_strtoupper($request->officename, $this->UTF_ENCODING))],
                    ['is_active', true]
                ]);
            })->exists()) {
                return $this->responseJson($this->MESSAGES['OFFICE_DUPLICATED'], null, 501);
            }

            $office->fk_site = $request->fk_site;
            $office->officename = trim(mb_strtoupper($request->officename, $this->UTF_ENCODING));
            $office->fk_userupdater = $this->user()->id;

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

    public function destroy(OfficeRequest $request)
    {
        try {
            $office = Office::find($request->id);

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

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

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

    public function changeStatus(OfficeRequest $request)
    {
        try {
            $office = Office::find($request->id);

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

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

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

    public function changeVisiblity(OfficeRequest $request)
    {
        try {
            $office = Office::find($request->id);

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

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

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

    public function getOfficeBySite(OfficeRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator();

            $offices = Site::with(['offices' => function ($offices) use ($request, $isSystemAdministrator) {
                $offices->where([
                    ['is_active', !$this->hasSpecial($request->fk_office)],
                ])->when(!$isSystemAdministrator, function ($query) {
                    $query->where([
                        ['visible', true]
                    ]);
                })->when(isset($request->available) && $request->available, function ($query) {
                    $query->where('available', true);
                });
            }])->find($request->fk_site)->offices;

            return $this->responseJson(null, $offices, 200);
        } catch (Exception $ex) {
            $this->generateLog('office_errors', $ex);
            return $this->responseJson($this->MESSAGES['OFFICE_BY_SITE'], null, 501);
        }
    }

    public function show(OfficeRequest $request)
    {
        try {
            $office_query = Office::select('id', 'officename')->findOrFail($request->id)
                ->load(['positions' => function ($position_query) {
                    $position_query->withCount('collaborators');
                }, 'collaborators']);

            return $this->responseJson(null, $office_query, 200);
        } catch (Exception $ex) {
            $this->generateLog('office_errors', $ex);
            return $this->responseJson($this->MESSAGES['OFFICE_SHOW'], null, 501);
        }
    }
}
