<?php

namespace App\Http\Controllers\api;

use Exception;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\BrandRequest;
use App\Models\Application\Brand;

class BrandController extends Controller
{
    protected $MESSAGES = [
        'INDEX' => 'WARNING.BRAND_INDEX',
        'STORE' => 'WARNING.BRAND_STORE',
        'UPDATE' => 'WARNING.BRAND_UPDATE',
        'DESTROY' => 'WARNING.BRAND_DESTROY',
        'DUPLICATED' => 'WARNING.BRAND_DUPLICATED',
        'STATUS' => 'WARNING.BRAND_STATUS',
        'VISIBLE' => 'WARNING.BRAND_VISIBLE',
        'LIST' => 'WARNING.BRAND_LIST',
        'SHOW' => 'WARNING.BRAND_SHOW',
    ];

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

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

            $brands = Brand::with(['user_creator', 'user_updater'])->where([
                ['fk_site', $request->fk_site],
                ['fk_office', $request->fk_office],
                ['is_active', !$this->hasSpecial($request->fk_office)]
            ])->when(!$isSystemAdministrator, function ($query) {
                $query->where([
                    ['visible', true]
                ]);
            })->withCount('models')->orderBy('id')->get();

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

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

    public function store(Request $request)
    {
        try {
            $isDuplicated = Brand::where([
                ['fk_site', $request->fk_site],
                ['fk_office', $request->fk_office],
                ['brandname', mb_strtoupper($request->brandname, $this->UTF_ENCODING)],
                ['is_active', true]
            ])->exists();

            if ($isDuplicated) {
                return $this->responseJson($this->MESSAGES['DUPLICATED'], null, 501);
            }

            Brand::create([
                'fk_site' => $request->fk_site,
                'fk_office' => $request->fk_office,
                'brandname' => mb_strtoupper($request->brandname, $this->UTF_ENCODING),
                'fk_usercreator' => $this->user()->id,
            ]);

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

    public function update(BrandRequest $request)
    {
        try {
            $brand = Brand::find($request->id);
            $route = $request->route()->getName();

            $actions = [
                'brand.update' => function () use ($request, $brand) {
                    $this->updateBrand($request, $brand);
                },
                'brand.changeStatus' => function () use ($request, $brand) {
                    $this->updateBrandBooleanStatus($request, $brand, 'status');
                },
                'brand.changeVisibility' => function () use ($request, $brand) {
                    $this->updateBrandBooleanStatus($request, $brand, 'visible');
                },
            ];

            if (array_key_exists($route, $actions)) {
                $actions[$route]();
            }

            return $this->responseJson(null, true, 201);
        } catch (Exception $ex) {
            $responses = [
                'brand.update' => $this->MESSAGES['UPDATE'],
                'brand.changeStatus' => $this->MESSAGES['STATUS'],
                'brand.changeVisibility' => $this->MESSAGES['VISIBLE']
            ];

            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($responses[$route], null, 501);
        }
    }

    private function updateBrand(BrandRequest $request, Brand $brand)
    {
        $isDuplicated = Brand::where([
            ['fk_office', $request->fk_office],
            ['brandname', mb_strtoupper($request->brandname, $this->UTF_ENCODING)],
            ['is_active', true]
        ])->where('id', '!=', $brand->id)->exists();

        if ($isDuplicated) {
            throw new Exception($this->MESSAGES['DUPLICATED']);
        }

        $brand->update([
            'brandname' => mb_strtoupper($request->brandname, $this->UTF_ENCODING),
            'fk_userupdater' => $this->user()->id,
        ]);
    }

    private function updateBrandBooleanStatus(BrandRequest $request, Brand $brand, $type = 'status')
    {
        $brand->update([
            $this->fields[$type] => $request->{$this->fields[$type]},
            'fk_userupdater' => $this->user()->id,
        ]);
    }

    public function destroy(BrandRequest $request)
    {
        try {
            $brand = Brand::find($request->id);

            $brand->update([
                'is_active' => $this->hasSpecial($request->fk_office),
                'fk_userupdater' => $this->user()->id,
            ]);

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

    public function list(BrandRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator($request->fk_office);

            $brands = Brand::select('id', 'brandname')->where([
                ['fk_office', $request->fk_office],
                ['available', true],
                ['is_active', true]
            ])->when(!$isSystemAdministrator, function ($query) {
                $query->where('visible', true);
            })->orderBy('brandname')->get();

            return $this->responseJson(null, $brands, 201);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['LIST'], null, 501);
        }
    }

    public function show(BrandRequest $request)
    {
        try {
            $brand = Brand::findOrFail($request->id)
                ->load(['models', 'user_creator'])
                ->loadCount('models')
                ->only(['id', 'brandname', 'models', 'models_count', 'created_at', 'user_creator']);
            return $this->responseJson(null, $brand, 201);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['SHOW'], null, 501);
        }
    }
}
