<?php

namespace App\Modules\Auth\Controllers;

use App\Core\BaseApiController;
use App\Modules\Auth\Models\RoleModel;
use App\Modules\Auth\Models\UserModel;
use App\Modules\Auth\Models\UserRoleModel;
use CodeIgniter\HTTP\ResponseInterface;

/**
 * User API (ADMIN only). List by role; create/update/delete users (for teachers).
 */
class UserController extends BaseApiController
{
    /**
     * GET /api/users?role=GURU_MAPEL
     * Returns users with optional role filter. Response: [{ id, name, email }, ...]
     */
    public function index(): ResponseInterface
    {
        $roleCode = $this->request->getGet('role');
        if ($roleCode === null || $roleCode === '') {
            return $this->errorResponse('Query parameter role is required', null, null, 422);
        }

        $roleModel = new RoleModel();
        $role      = $roleModel->findByCode((string) $roleCode);
        if (!$role) {
            return $this->successResponse([], 'Users');
        }

        $userRoleModel = new UserRoleModel();
        $db            = \Config\Database::connect();
        $builder       = $db->table('user_roles');
        $builder->select('user_id');
        $builder->where('role_id', $role->id);
        $rows   = $builder->get()->getResultArray();
        $userIdList = array_values(array_unique(array_map(static fn ($r) => (int) $r['user_id'], $rows)));
        if ($userIdList === []) {
            return $this->successResponse([], 'Users');
        }

        $userModel = new UserModel();
        $users     = $userModel->whereIn('id', $userIdList)->findAll();
        $data      = [];
        foreach ($users as $u) {
            $data[] = [
                'id'    => (int) $u->id,
                'name'  => (string) $u->name,
                'email' => (string) $u->email,
            ];
        }
        usort($data, static fn ($a, $b) => strcasecmp($a['name'], $b['name']));

        return $this->successResponse($data, 'Users');
    }

    /**
     * POST /api/users
     * Body (baru): name, email, password, roles[] (isi: GURU_MAPEL dan/atau WALI_KELAS).
     * Body (lama, tetap didukung): name, email, password, role_code.
     */
    public function store(): ResponseInterface
    {
        $payload = $this->request->getJSON(true) ?? [];
        $name    = trim($payload['name'] ?? '');
        $email   = trim($payload['email'] ?? '');
        $password = $payload['password'] ?? '';
        $rolesInput = $payload['roles'] ?? null;
        $roleCode   = $payload['role_code'] ?? null; // fallback lama

        if ($name === '' || $email === '' || $password === '') {
            return $this->errorResponse('Name, email, and password are required', null, null, 422);
        }

        $roleModel = new RoleModel();
        $allowedCodes = ['GURU_MAPEL', 'WALI_KELAS'];

        // Normalisasi roles: jika roles[] tidak ada, pakai role_code tunggal (kompatibilitas lama)
        $roleCodes = [];
        if (is_array($rolesInput)) {
            foreach ($rolesInput as $rc) {
                $rc = (string) $rc;
                if (in_array($rc, $allowedCodes, true)) {
                    $roleCodes[] = $rc;
                }
            }
            $roleCodes = array_values(array_unique($roleCodes));
        } elseif (is_string($roleCode) && $roleCode !== '') {
            if (! in_array($roleCode, $allowedCodes, true)) {
                return $this->errorResponse('role_code must be GURU_MAPEL or WALI_KELAS', null, null, 422);
            }
            $roleCodes = [$roleCode];
        }

        if ($roleCodes === []) {
            return $this->errorResponse('At least one role (GURU_MAPEL or WALI_KELAS) is required', null, null, 422);
        }

        $userModel = new UserModel();
        $existing = $userModel->findByEmail($email);
        if ($existing) {
            return $this->errorResponse('Email already registered', null, null, 422);
        }

        $userModel->skipValidation(false);
        $id = $userModel->insert([
            'name'          => $name,
            'email'         => $email,
            'password_hash' => password_hash($password, PASSWORD_DEFAULT),
            'is_active'     => 1,
        ]);
        if ($id === false) {
            return $this->errorResponse(implode(' ', $userModel->errors()), $userModel->errors(), null, 422);
        }

        $userRoleModel = new UserRoleModel();
        foreach ($roleCodes as $code) {
            $role = $roleModel->findByCode($code);
            if ($role) {
                $userRoleModel->insert(['user_id' => $id, 'role_id' => $role->id]);
            }
        }

        $user = $userModel->find($id);
        return $this->successResponse([
            'id'    => (int) $user->id,
            'name'  => (string) $user->name,
            'email' => (string) $user->email,
        ], 'User created', null, ResponseInterface::HTTP_CREATED);
    }

    /**
     * PUT /api/users/{id}
     * Body (baru): name?, email?, password?, roles[] (GURU_MAPEL/WALI_KELAS)
     * Body (lama, tetap didukung): role_code tunggal.
     */
    public function update(int $id): ResponseInterface
    {
        $userModel = new UserModel();
        $user = $userModel->find($id);
        if (! $user) {
            return $this->errorResponse('User not found', null, null, 404);
        }

        $payload = $this->request->getJSON(true) ?? [];
        $data = [];
        if (array_key_exists('name', $payload)) {
            $data['name'] = trim($payload['name']);
        }
        if (array_key_exists('email', $payload)) {
            $data['email'] = trim($payload['email']);
        }
        if (isset($payload['password']) && $payload['password'] !== '') {
            $data['password_hash'] = password_hash($payload['password'], PASSWORD_DEFAULT);
        }

        if ($data !== []) {
            $validation = \Config\Services::validation();
            $rules = [
                'name'  => 'required|max_length[255]',
                'email' => 'required|valid_email|max_length[255]|is_unique[users.email,id,' . $id . ']',
            ];
            $toValidate = [
                'name'  => $data['name'] ?? $user->name,
                'email' => $data['email'] ?? $user->email,
            ];
            if (! $validation->setRules($rules)->run($toValidate)) {
                return $this->errorResponse(implode(' ', $validation->getErrors()), $validation->getErrors(), null, 422);
            }
            $userModel->skipValidation(true);
            $userModel->update($id, $data);
        }

        // Sinkronisasi roles
        $rolesInput = $payload['roles'] ?? null;
        $roleCode   = $payload['role_code'] ?? null; // fallback lama
        $allowedCodes = ['GURU_MAPEL', 'WALI_KELAS'];

        $roleCodes = null;
        if (is_array($rolesInput)) {
            $roleCodes = [];
            foreach ($rolesInput as $rc) {
                $rc = (string) $rc;
                if (in_array($rc, $allowedCodes, true)) {
                    $roleCodes[] = $rc;
                }
            }
            $roleCodes = array_values(array_unique($roleCodes));
        } elseif (isset($roleCode) && in_array($roleCode, $allowedCodes, true)) {
            // kompatibilitas lama: satu role_code
            $roleCodes = [$roleCode];
        }

        if (is_array($roleCodes)) {
            $roleModel = new RoleModel();
            $userRoleModel = new UserRoleModel();
            $db = \Config\Database::connect();

            // Hapus semua role sebelumnya, lalu insert sesuai request
            $db->table('user_roles')->where('user_id', $id)->delete();

            foreach ($roleCodes as $code) {
                $role = $roleModel->findByCode($code);
                if ($role) {
                    $userRoleModel->insert(['user_id' => $id, 'role_id' => $role->id]);
                }
            }
        }

        $updated = $userModel->find($id);
        return $this->successResponse([
            'id'    => (int) $updated->id,
            'name'  => (string) $updated->name,
            'email' => (string) $updated->email,
        ], 'User updated');
    }

    /**
     * DELETE /api/users/{id}
     */
    public function delete(int $id): ResponseInterface
    {
        $userModel = new UserModel();
        if (! $userModel->find($id)) {
            return $this->errorResponse('User not found', null, null, 404);
        }
        $userModel->delete($id);
        return $this->successResponse(null, 'User deleted');
    }
}
