<?php

namespace App\Controllers\Api;

use App\Libraries\JwtAuth;

class AuthController extends BaseApiController
{
    /**
     * POST api/auth/login
     * Body: { "phone": "256712345678", "pin": "123456" }
     * Returns: { "data": { "token": "...", "user": { "id", "phone", "role" } }, "error": null }
     */
    public function login()
    {
        $phone = $this->request->getJSON(true)['phone'] ?? $this->request->getPost('phone');
        $pin   = $this->request->getJSON(true)['pin'] ?? $this->request->getPost('pin');

        if (empty($phone) || empty($pin)) {
            return $this->error('Phone and PIN are required', 400);
        }

        $phone = $this->normalizePhone($phone);
        if (! $phone) {
            return $this->error('Invalid phone format. Use +256XXXXXXXXX', 400);
        }

        if (strlen($pin) !== 6 || ! ctype_digit($pin)) {
            return $this->error('PIN must be 6 digits', 400);
        }

        $db  = \Config\Database::connect();
        $row = $db->table('users')->where('phone', $phone)->get()->getRow();
        if (! $row) {
            return $this->error('Invalid phone or PIN', 401);
        }

        if (! password_verify($pin, $row->pin_hash)) {
            return $this->error('Invalid phone or PIN', 401);
        }

        if (isset($row->jambo_status) && $row->jambo_status === 'inactive') {
            return $this->error('Account deactivated', 401);
        }

        $token = JwtAuth::generate((int) $row->id, $row->phone, $row->role ?? 'user');

        return $this->success([
            'token' => $token,
            'user'  => [
                'id'    => (int) $row->id,
                'phone' => $row->phone,
                'role'  => $row->role ?? 'user',
            ],
        ]);
    }

    /**
     * POST api/auth/register
     * Body: { "phone": "256712345678", "pin": "123456", "role": "user"|"driver" }
     */
    public function register()
    {
        $data = $this->request->getJSON(true) ?: $this->request->getPost();
        $phone = $data['phone'] ?? '';
        $pin   = $data['pin'] ?? '';
        $role  = $data['role'] ?? 'user';

        if (empty($phone) || empty($pin)) {
            return $this->error('Phone and PIN are required', 400);
        }

        $phone = $this->normalizePhone($phone);
        if (! $phone) {
            return $this->error('Invalid phone format. Use +256XXXXXXXXX', 400);
        }

        if (strlen($pin) !== 6 || ! ctype_digit($pin)) {
            return $this->error('PIN must be 6 digits', 400);
        }

        if (! in_array($role, ['user', 'driver'], true)) {
            $role = 'user';
        }

        $db = \Config\Database::connect();
        if ($db->table('users')->where('phone', $phone)->countAllResults() > 0) {
            return $this->error('Phone already registered', 409);
        }

        $db = \Config\Database::connect();
        $db->table('users')->insert([
            'username'     => 'user_' . $phone,
            'phone'        => $phone,
            'pin_hash'     => password_hash($pin, PASSWORD_DEFAULT),
            'role'         => $role,
            'jambo_status' => 'active',
            'active'       => 1,
            'created_at'   => date('Y-m-d H:i:s'),
            'updated_at'   => date('Y-m-d H:i:s'),
        ]);
        $userId = (int) $db->insertID();

        $token = JwtAuth::generate($userId, $phone, $role);

        return $this->success([
            'token' => $token,
            'user'  => [
                'id'    => (int) $userId,
                'phone' => $phone,
                'role'  => $role,
            ],
        ], 201);
    }

    /**
     * GET api/auth/me (requires Bearer token)
     */
    public function me()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }

        $db   = \Config\Database::connect();
        $row  = $db->table('users')->where('id', $user->id)->get()->getRow();
        $pointsBalance = isset($row->points_balance) ? (int) $row->points_balance : 0;

        return $this->success([
            'id'             => (int) $user->id,
            'phone'          => $user->phone,
            'role'           => $user->role ?? 'user',
            'points_balance' => $pointsBalance,
        ]);
    }

    /**
     * PATCH api/auth/change-phone (requires Bearer token)
     * Body: { "new_phone": "256712345678", "current_pin": "123456" }
     */
    public function changePhone()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }

        $data   = $this->request->getJSON(true) ?: [];
        $newPhone = $data['new_phone'] ?? '';
        $currentPin = $data['current_pin'] ?? '';

        if (empty($newPhone) || empty($currentPin)) {
            return $this->error('New phone and current PIN are required', 400);
        }

        $newPhone = $this->normalizePhone($newPhone);
        if (! $newPhone) {
            return $this->error('Invalid phone format. Use 9 digits starting with 7', 400);
        }

        if (strlen($currentPin) !== 6 || ! ctype_digit($currentPin)) {
            return $this->error('PIN must be 6 digits', 400);
        }

        $db  = \Config\Database::connect();
        $row = $db->table('users')->where('id', $user->id)->get()->getRow();
        if (! $row || ! password_verify($currentPin, $row->pin_hash)) {
            return $this->error('Current PIN is incorrect', 401);
        }

        if ($db->table('users')->where('phone', $newPhone)->where('id !=', $user->id)->countAllResults() > 0) {
            return $this->error('That phone number is already registered', 409);
        }

        $db->table('users')->where('id', $user->id)->update([
            'username'   => 'user_' . $newPhone,
            'phone'      => $newPhone,
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        $token = JwtAuth::generate((int) $user->id, $newPhone, $row->role ?? 'user');

        return $this->success([
            'token' => $token,
            'user'  => [
                'id'    => (int) $user->id,
                'phone' => $newPhone,
                'role'  => $row->role ?? 'user',
            ],
        ]);
    }

    /**
     * PATCH api/auth/change-pin (requires Bearer token)
     * Body: { "current_pin": "123456", "new_pin": "654321" }
     */
    public function changePin()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }

        $data        = $this->request->getJSON(true) ?: [];
        $currentPin  = $data['current_pin'] ?? '';
        $newPin      = $data['new_pin'] ?? '';

        if (empty($currentPin) || empty($newPin)) {
            return $this->error('Current PIN and new PIN are required', 400);
        }

        if (strlen($newPin) !== 6 || ! ctype_digit($newPin)) {
            return $this->error('New PIN must be 6 digits', 400);
        }

        if (strlen($currentPin) !== 6 || ! ctype_digit($currentPin)) {
            return $this->error('Current PIN must be 6 digits', 400);
        }

        $db  = \Config\Database::connect();
        $row = $db->table('users')->where('id', $user->id)->get()->getRow();
        if (! $row || ! password_verify($currentPin, $row->pin_hash)) {
            return $this->error('Current PIN is incorrect', 401);
        }

        $db->table('users')->where('id', $user->id)->update([
            'pin_hash'   => password_hash($newPin, PASSWORD_DEFAULT),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        return $this->success(['message' => 'PIN updated']);
    }

    /**
     * POST api/auth/delete-account (requires Bearer token)
     * Body: { "pin": "123456" }
     * Permanently deletes consumer accounts (role user). Orders are kept with user_id set to NULL.
     */
    public function deleteAccount()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }

        if (($user->role ?? 'user') !== 'user') {
            return $this->error('Account deletion is only available for customer accounts', 403);
        }

        $data = $this->request->getJSON(true) ?: [];
        $pin  = $data['pin'] ?? '';
        if (strlen($pin) !== 6 || ! ctype_digit($pin)) {
            return $this->error('PIN must be 6 digits', 400);
        }

        $db  = \Config\Database::connect();
        $row = $db->table('users')->where('id', $user->id)->get()->getRow();
        if (! $row || ! password_verify($pin, $row->pin_hash)) {
            return $this->error('PIN is incorrect', 400);
        }

        $activeOrders = $db->table('orders')
            ->where('user_id', $user->id)
            ->whereIn('status', ['pending', 'paid', 'dispatched'])
            ->countAllResults();
        if ($activeOrders > 0) {
            return $this->error(
                'You have active orders. Please wait until they are delivered or cancelled before deleting your account.',
                409
            );
        }

        $db->transStart();
        $db->table('users')->where('id', $user->id)->delete();
        $db->transComplete();

        if (! $db->transStatus()) {
            return $this->error('Could not delete account', 500);
        }

        return $this->success(['deleted' => true]);
    }

    private function normalizePhone(string $phone): ?string
    {
        $phone = preg_replace('/\D/', '', $phone);
        if (strlen($phone) === 9 && str_starts_with($phone, '7')) {
            return '256' . $phone;
        }
        if (strlen($phone) === 12 && str_starts_with($phone, '256')) {
            return $phone;
        }

        return null;
    }
}
