<?php

namespace App\Http\Controllers\Admin;

use App\Models\User;
use App\Utils\Helper;
use App\Enums\UserType;
use App\Models\Company;
use App\Enums\ActionType;
use App\Models\UserOwner;
use App\Models\UserCompany;
use Laravolt\Avatar\Avatar;
use Illuminate\Http\Request;
use App\Enums\OriginStatusType;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rules\Password;
use App\Http\Controllers\Core\BaseResourceController;
use App\Models\Department;

class UsersController extends BaseResourceController
{
  protected $model = User::class;

  protected function indexQuery($query, $request)
  {
    $query->with('owner:users.id,users.name');
    $query->when($request->filled("role"), fn($q) => $q->where("role", $request->role));
    $query->when($request->filled("status"), fn($q) => $q->where("status", $request->status));
    $query->filterDepartment();

    return $query;
  }

  protected function getPage($request, $id = null): array
  {
    return [
      "name" => "users",
      "inertia" => "Users",
      "label" => "Pengguna",
      "url" => "/admin/users",
      "fields" => \App\Utils\Helper::getFormFields($this->validation($request)),
    ];
  }

  protected function validation($request, $id = null): array
  {
    return [
      "validation" => [
        "manager_id" => [
          Rule::requiredIf(function () use ($request) {
            return $this->isAdmin && in_array($request->role, [UserType::User]);
          })
        ],
        "name" => "required|string|max:255",
        "username" => ["nullable", "string", "max:255", Rule::unique(User::class, "username")->ignore($id)],
        "email" => "required|string|email|max:255|unique:" . User::class . ",email," . $id,
        "password" => ["nullable", "confirmed", Rules\Password::defaults()],
        "role" => "nullable|string|max:255",
        "picture" => ["nullable", ...[is_file($request->picture) ? ["image", "mimes:jpeg,png,jpg,gif,svg,webp,avif", "max:2048"] : []]],
        "status" => "nullable",
        "phone" => ["nullable", "numeric", "digits_between:10,13", "starts_with:08,02", Rule::unique(User::class, "phone")->ignore($id)],
      ],
      "default" => [
        "status" => OriginStatusType::Active,
      ],
    ];
  }

  protected function getFormData($request, $user = null): array
  {
    $formPageData = $this->isFormPage ? $this->getFormPageData($request, $user) : [];

    return [
      "page" => $this->page,
      "isAdmin" => $this->isAdmin,
      "roles" => UserType::getValues(),
      "status" => OriginStatusType::getValues(),
      ...$formPageData
    ];
  }

  protected function getFormPageData($request, $user)
  {
    $defaultValues = ["role", "manager_id"];

    if (!empty($user)) {
      $array = collect($user->toArray())->only($defaultValues)->toArray();
      $request->merge([...$array, ...$request->all()]);
    }

    if (auth()->user()->role == UserType::Manager) {
      $request->merge([
        "manager_id" => auth()->user()->id,
        "role" => UserType::User,
      ]);
    }

    $owners = [];
    if ($this->isAdmin && in_array($request->role, [UserType::User])) {
      $owners = User::select(["id", "id as value", "name as label"])
        ->when($request->role == UserType::User, function ($query) {
          $query->whereIn("role", [UserType::Manager]);
        })
        ->where("status", OriginStatusType::Active)
        ->get();
    }

    $companies = [];

    $companyIds = [];
    if (in_array(auth()->user()->role, [UserType::Director, UserType::Manager])) {
      if ($request->manager_id) {
        $companyIds = UserCompany::where('user_id', $request->manager_id)->pluck('company_id')->toArray();
      }

      $companies = Company::selectOptions()->where('status', OriginStatusType::Active);
      if (!empty($companyIds)) {
        $companies = $companies->whereIn('id', $companyIds);
      }

      if (empty($companyIds) && auth()->user()->role != UserType::Director) {
        $companies = $companies->whereIn('id', $companyIds);
      }

      if (empty($companyIds) && auth()->user()->role == UserType::Director && in_array($request->role, [UserType::User])) {
        $companies = $companies->whereIn('id', $companyIds);
      }

      $companies = $companies->get();
    }

    if (!empty($user)) {
      $user->load([
        'owner',
        'companies' => function ($query) {
          return $query->selectOptions("companies.id", "companies.name")->where('status', OriginStatusType::Active);
        }
      ]);
      $user->manager_id = $user->owner ? $user->owner->id : null;
      $user->company_id = $user->companies;
    }

    $this->modelInstance = $user;
    $data = [
      "owners" => $owners,
      "companies" => $companies,
    ];
    return $data;
  }

  protected function beforeSave(array $validatedData, Request $request): array
  {
    if ($request->file("picture")) {
      $file = Storage::disk("public")->put("picture", $request->file("picture"));
      $validatedData["picture"] = $file ? "/storage/$file" : null;
    }

    if (empty($validatedData["picture"])) {
      $avatar = new Avatar();
      $validatedData["picture"] = $avatar->create($request->name)
        ->setBackground("#7842f5")
        ->setForeground("#ffffff")
        ->setDimension(200)
        ->setFontSize(100)
        ->toBase64();
    }

    if (!empty($request->password)) {
      $validatedData["password"] = Hash::make($request->password);
    } else {
      unset($validatedData["password"]);
    }

    unset($validatedData["manager_id"]);

    if (auth()->user()->role == UserType::Manager) {
      $validatedData["role"] = UserType::User;
    }

    return $validatedData;
  }

  protected function afterSave($model, Request $request)
  {
    if (!$request->id) {
      $emailParts = explode("@", $model->email);
      $username = preg_replace("/[^A-Za-z0-9]/", "-", $emailParts[0] . $model->id);
      $model->username = $username;
      $model->save();
    }

    $this->updateMember($model);
    $this->saveCompany($request, $model);
    $this->saveDepartment($request, $model);
  }

  protected function beforeSoftDelete($model, Request $request)
  {
    $model->username = "$model->username|deleted:" . time();
    $model->email = "$model->email|deleted:" . time();
    $model->save();
  }

  protected function getAuthorize(Request $request, $user = null, $action = ActionType::Read)
  {
    if ($this->isAdmin)
      return true;
    if (!$user)
      return true;

    $allowedEditedRole = [UserType::User];
    return in_array($user->role, $allowedEditedRole);
  }

  protected function updateMember($user)
  {
    $request = request();
    $managerId = $request->manager_id ?? auth()->id();

    $memberData = [
      'owner_id' => $managerId,
      'user_id' => $user->id,
    ];

    $member = UserOwner::where($memberData)->first();
    if (!empty($member)) {
      $member->update($memberData);
    } else {
      UserOwner::create($memberData);
    }
  }

  protected function saveDepartment($request, $user)
  {
    if (auth()->user()->role != UserType::Manager)
      return;

    $department = Department::active($request)->first();

    $department->userDepartments()->updateOrCreate(
      ['user_id' => $user->id],
      [
        'manager_id' => auth()->id(),
        'type' => UserType::User,
      ]
    );
  }

  protected function saveCompany($request, $user)
  {
    $newData = collect($request->company_id)->toArray();
    $latestData = collect($newData)->pluck("value")->whereNotNull()->toArray();
    $deleteds = UserCompany::where("user_id", $user->id)->whereNotIn("company_id", $latestData)->get();

    $user->load('owners');
    $memberIds = $user->owners->pluck('user_id')->toArray();
    $deletedMemberCompany = UserCompany::whereIn("user_id", $memberIds)->whereNotIn("company_id", $latestData)->get();

    if ($deleteds->isNotEmpty()) {
      foreach ($deleteds as $deleted) {
        $deleted->delete();
      }
    }
    if ($deletedMemberCompany->isNotEmpty()) {
      foreach ($deletedMemberCompany as $deleted) {
        $deleted->delete();
      }
    }
    if (empty($newData))
      return;

    foreach ($newData as $data) {
      $value = $data["value"];
      $exist = UserCompany::where("user_id", $user->id)->where("company_id", $value)->first();

      if (empty($exist)) {
        UserCompany::create([
          "user_id" => $user->id,
          "company_id" => $value,
        ]);
      }
    }
  }
}
