<?php

namespace App\Controllers;

use App\Models\UserModel;
use App\Models\KoperasiModel;
use App\Models\SystemSettingModel;

class AuthController extends BaseController
{
    private function generateJWT($userData)
    {
        $header = json_encode(['alg' => 'HS256', 'typ' => 'JWT']);
        $payload = json_encode([
            'iss' => 'kopdigi',
            'iat' => time(),
            'exp' => time() + 3600,
            'uid' => $userData['id'],
            'email' => $userData['email'],
            'role_id' => $userData['role_id'],
            'nama' => $userData['nama']
        ]);
        
        $base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
        $base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
        
        $secret = env('JWT_SECRET', 'kopmart_super_secret_jwt_key_2026_xyz123_abc456_qwe789');
        $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secret, true);
        $base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
        
        return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
    }

    private function validateJWT($token)
    {
        $tokenParts = explode('.', $token);
        if (count($tokenParts) !== 3) return false;

        $header = base64_decode(str_replace(['-', '_'], ['+', '/'], $tokenParts[0]));
        $payload = base64_decode(str_replace(['-', '_'], ['+', '/'], $tokenParts[1]));
        $signatureProvided = $tokenParts[2];

        $secret = env('JWT_SECRET', 'kopmart_super_secret_jwt_key_2026_xyz123_abc456_qwe789');
        $signature = hash_hmac('sha256', $tokenParts[0] . "." . $tokenParts[1], $secret, true);
        $base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

        if ($base64UrlSignature !== $signatureProvided) return false;

        $payloadDecoded = json_decode($payload, true);
        if ($payloadDecoded['exp'] < time()) return false; // expired

        return $payloadDecoded;
    }

    public function register()
    {
        $userModel = new UserModel();

        $rules = [
            'name' => 'required',
            'email' => 'required|valid_email|is_unique[users.email]',
            'phone' => 'required',
            'password' => 'required|min_length[6]',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Validasi gagal',
                'errors' => $this->validator->getErrors()
            ])->setStatusCode(400);
        }

        $koperasiId = $this->request->getVar('koperasi_id') ?: null;
        $roleId = $this->request->getVar('role_id') ?: 4; // Default: Customer (4)

        $userData = [
            'koperasi_id' => $koperasiId,
            'role_id' => $roleId,
            'nama' => $this->request->getVar('name'),
            'email' => $this->request->getVar('email'),
            'phone' => $this->request->getVar('phone'),
            'password' => password_hash($this->request->getVar('password'), PASSWORD_BCRYPT),
            'status' => 'active',
            'created_at' => date('Y-m-d H:i:s'),
        ];

        $userId = $userModel->insert($userData);

        if (!$userId) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Gagal mendaftarkan pengguna'
            ])->setStatusCode(500);
        }

        // Add log
        $db = \Config\Database::connect();
        $db->table('audit_logs')->insert([
            'user_id' => $userId,
            'action' => 'Registrasi Akun Baru',
            'notes' => 'Pengguna baru berhasil melakukan registrasi.',
            'created_at' => date('Y-m-d H:i:s')
        ]);

        $createdUser = $userModel->find($userId);
        unset($createdUser['password']);

        return $this->response->setJSON([
            'status' => 'success',
            'message' => 'Pendaftaran berhasil',
            'data' => $createdUser
        ]);
    }

    public function login()
    {
        $userModel = new UserModel();
        $emailInput = trim($this->request->getVar('email') ?? '');
        $password = $this->request->getVar('password');

        // Translate simple usernames to full seeded emails for easy testing
        $email = $emailInput;
        if (strpos($emailInput, '@') === false) {
            if ($emailInput === 'superadmin') {
                $email = 'superadmin@kopdigi.id';
            } elseif ($emailInput === 'dinas') {
                $email = 'dinas@kopdigi.id';
            } elseif ($emailInput === 'admin') {
                $email = 'admin.kopa@kopdigi.id';
            } else {
                $email = $emailInput . '@kopdigi.id';
            }
        }

        $user = $userModel->where('email', $email)->first();

        if (!$user || !password_verify($password, $user['password'])) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Email atau password salah'
            ])->setStatusCode(401);
        }

        if ($user['status'] !== 'active') {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Akun Anda belum aktif atau ditangguhkan'
            ])->setStatusCode(403);
        }

        unset($user['password']);
        $token = $this->generateJWT($user);

        // Add log
        $db = \Config\Database::connect();
        $db->table('audit_logs')->insert([
            'user_id' => $user['id'],
            'action' => 'Login Berhasil',
            'notes' => 'Pengguna masuk ke dalam sistem.',
            'created_at' => date('Y-m-d H:i:s')
        ]);

        return $this->response->setJSON([
            'status' => 'success',
            'message' => 'Login berhasil',
            'token' => $token,
            'user' => $user
        ]);
    }

    public function profile()
    {
        $authHeader = $this->request->getServer('HTTP_AUTHORIZATION');
        if (!$authHeader) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Token otorisasi diperlukan'
            ])->setStatusCode(401);
        }

        $token = str_replace('Bearer ', '', $authHeader);
        $decoded = $this->validateJWT($token);

        if (!$decoded) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Token tidak valid atau kedaluwarsa'
            ])->setStatusCode(401);
        }

        $userModel = new UserModel();
        $user = $userModel->find($decoded['uid']);

        if (!$user) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Pengguna tidak ditemukan'
            ])->setStatusCode(404);
        }

        unset($user['password']);

        // Fetch cooperative details if Admin Koperasi
        $db = \Config\Database::connect();
        if ($user['koperasi_id']) {
            $user['koperasi'] = $db->table('koperasi')->where('id', $user['koperasi_id'])->get()->getRowArray();
        }

        return $this->response->setJSON([
            'status' => 'success',
            'data' => $user
        ]);
    }

    public function index()
    {
        $userModel = new UserModel();
        $db = \Config\Database::connect();
        $users = $userModel->findAll();

        foreach ($users as &$user) {
            unset($user['password']);
            $role = $db->table('roles')->where('id', $user['role_id'])->get()->getRowArray();
            $user['role_name'] = $role ? $role['role_name'] : 'Unknown';

            if ($user['koperasi_id']) {
                $coop = $db->table('koperasi')->where('id', $user['koperasi_id'])->get()->getRowArray();
                $user['koperasi_name'] = $coop ? $coop['nama_koperasi'] : '-';
            } else {
                $user['koperasi_name'] = '-';
            }
        }

        return $this->response->setJSON([
            'status' => 'success',
            'data' => $users
        ]);
    }

    public function updateUser($id)
    {
        $userModel = new UserModel();
        $user = $userModel->find($id);

        if (!$user) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Pengguna tidak ditemukan'
            ])->setStatusCode(404);
        }

        $nama = $this->request->getVar('nama');
        $email = $this->request->getVar('email');
        $roleId = $this->request->getVar('role_id');
        $status = $this->request->getVar('status');
        $koperasiId = $this->request->getVar('koperasi_id');

        $updateData = [
            'nama' => $nama,
            'email' => $email,
            'role_id' => $roleId,
            'status' => $status,
            'koperasi_id' => ($koperasiId === 'null' || empty($koperasiId)) ? null : $koperasiId
        ];

        $password = $this->request->getVar('password');
        if (!empty($password)) {
            $updateData['password'] = password_hash($password, PASSWORD_BCRYPT);
        }

        $userModel->update($id, $updateData);

        // Add log
        $db = \Config\Database::connect();
        $db->table('audit_logs')->insert([
            'user_id' => 1, // System admin
            'action' => 'Perbarui Pengguna',
            'notes' => "Memperbarui kredensial pengguna ID: {$id} ({$nama}).",
            'created_at' => date('Y-m-d H:i:s')
        ]);

        return $this->response->setJSON([
            'status' => 'success',
            'message' => 'Data pengguna berhasil diperbarui'
        ]);
    }

    public function updateProfile()
    {
        $authHeader = $this->request->getServer('HTTP_AUTHORIZATION');
        if (!$authHeader) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Token otorisasi diperlukan'
            ])->setStatusCode(401);
        }

        $token = str_replace('Bearer ', '', $authHeader);
        $decoded = $this->validateJWT($token);

        if (!$decoded) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Token tidak valid atau kedaluwarsa'
            ])->setStatusCode(401);
        }

        $userId = $decoded['uid'];
        $userModel = new UserModel();
        $user = $userModel->find($userId);

        if (!$user) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Pengguna tidak ditemukan'
            ])->setStatusCode(404);
        }

        $nama = $this->request->getVar('nama') ?: $user['nama'];
        $email = $this->request->getVar('email') ?: $user['email'];
        $phone = $this->request->getVar('phone') ?: $user['phone'];
        $nik = $this->request->getVar('nik') ?: $user['nik'];
        $alamatUtama = $this->request->getVar('alamat_utama') ?: $user['alamat_utama'];
        $bankName = $this->request->getVar('bank_name') ?: $user['bank_name'];
        $noRekening = $this->request->getVar('no_rekening') ?: $user['no_rekening'];
        $verificationStatus = $this->request->getVar('verification_status') ?: $user['verification_status'];

        // Validate email uniqueness if changed
        if ($email !== $user['email']) {
            $existing = $userModel->where('email', $email)->first();
            if ($existing) {
                return $this->response->setJSON([
                    'status' => 'error',
                    'message' => 'Email sudah digunakan oleh akun lain'
                ])->setStatusCode(400);
            }
        }

        $updateData = [
            'nama' => $nama,
            'email' => $email,
            'phone' => $phone,
            'nik' => $nik,
            'alamat_utama' => $alamatUtama,
            'bank_name' => $bankName,
            'no_rekening' => $noRekening,
            'verification_status' => $verificationStatus,
        ];

        // Handle password update if provided
        $password = $this->request->getVar('password');
        if (!empty($password)) {
            $updateData['password'] = password_hash($password, PASSWORD_BCRYPT);
        }

        // Handle uploaded or base64 profile picture
        $fotoProfil = $this->request->getVar('foto_profil');
        if (!empty($fotoProfil)) {
            if (strpos($fotoProfil, 'data:image') === 0) {
                // Base64 string
                $imgData = explode(',', $fotoProfil);
                $decodedImg = base64_decode($imgData[1]);
                $fileName = 'profile_' . $userId . '_' . time() . '.png';
                $filePath = FCPATH . 'uploads/profile/' . $fileName;
                
                if (!is_dir(FCPATH . 'uploads/profile')) {
                    mkdir(FCPATH . 'uploads/profile', 0777, true);
                }
                file_put_contents($filePath, $decodedImg);
                $updateData['foto_profil'] = 'uploads/profile/' . $fileName;
            } else {
                $updateData['foto_profil'] = $fotoProfil;
            }
        }

        // Handle uploaded or base64 QRIS image
        $qrisPath = $this->request->getVar('qris_path');
        if (!empty($qrisPath)) {
            if (strpos($qrisPath, 'data:image') === 0) {
                // Base64 string
                $imgData = explode(',', $qrisPath);
                $decodedImg = base64_decode($imgData[1]);
                $fileName = 'qris_' . $userId . '_' . time() . '.png';
                $filePath = FCPATH . 'uploads/profile/' . $fileName;
                
                if (!is_dir(FCPATH . 'uploads/profile')) {
                    mkdir(FCPATH . 'uploads/profile', 0777, true);
                }
                file_put_contents($filePath, $decodedImg);
                $updateData['qris_path'] = 'uploads/profile/' . $fileName;
            } else {
                $updateData['qris_path'] = $qrisPath;
            }
        }

        $userModel->update($userId, $updateData);

        // Add log
        $db = \Config\Database::connect();
        $db->table('audit_logs')->insert([
            'user_id' => $userId,
            'action' => 'Perbarui Profil',
            'notes' => 'Pengguna memperbarui informasi profil pribadi dan finansial.',
            'created_at' => date('Y-m-d H:i:s')
        ]);

        $updatedUser = $userModel->find($userId);
        unset($updatedUser['password']);

        return $this->response->setJSON([
            'status' => 'success',
            'message' => 'Profil berhasil diperbarui',
            'user' => $updatedUser
        ]);
    }

    public function verifyUser($id)
    {
        $userModel = new UserModel();
        $user = $userModel->find($id);

        if (!$user) {
            return $this->response->setJSON([
                'status' => 'error',
                'message' => 'Pengguna tidak ditemukan'
            ])->setStatusCode(404);
        }

        $verificationStatus = $this->request->getVar('verification_status') ?: 'VERIFIED';
        
        $userModel->update($id, ['verification_status' => $verificationStatus]);

        // Add audit log
        $db = \Config\Database::connect();
        $db->table('audit_logs')->insert([
            'user_id' => 1, // System admin
            'action' => 'Verifikasi Anggota',
            'notes' => "Mengubah status verifikasi pengguna ID: {$id} ({$user['nama']}) menjadi {$verificationStatus}.",
            'created_at' => date('Y-m-d H:i:s')
        ]);

        return $this->response->setJSON([
            'status' => 'success',
            'message' => 'Status verifikasi berhasil diperbarui'
        ]);
    }

    public function forgotPassword()
    {
        $email = $this->request->getVar('email');
        if (empty($email)) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Email tidak boleh kosong'])->setStatusCode(400);
        }

        $userModel = new UserModel();
        $user = $userModel->where('email', $email)->first();

        if (!$user) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Email tidak ditemukan di sistem'])->setStatusCode(404);
        }

        // Generate token
        $token = bin2hex(random_bytes(32));
        $expires = date('Y-m-d H:i:s', time() + 3600); // 1 hour

        $userModel->update($user['id'], [
            'reset_token' => $token,
            'reset_expires_at' => $expires
        ]);

        // Fetch SMTP Settings
        $settingModel = new SystemSettingModel();
        $settings = [];
        foreach ($settingModel->findAll() as $s) {
            $settings[$s['key_name']] = $s['key_value'];
        }

        if (empty($settings['smtp_host'])) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Konfigurasi SMTP belum diatur oleh admin'])->setStatusCode(500);
        }

        // Send Email
        $emailService = \Config\Services::email();

        $config = [
            'protocol'   => 'smtp',
            'SMTPHost'   => $settings['smtp_host'] ?? '',
            'SMTPUser'   => $settings['smtp_user'] ?? '',
            'SMTPPass'   => $settings['smtp_pass'] ?? '',
            'SMTPPort'   => $settings['smtp_port'] ?? 465,
            'SMTPCrypto' => $settings['smtp_crypto'] ?? 'ssl',
            'mailType'   => 'html',
            'charset'    => 'utf-8'
        ];

        $emailService->initialize($config);
        $fromEmail = $settings['smtp_from'] ?? 'noreply@kopdigi.go.id';
        $appName = $settings['app_name'] ?? 'Koperasi Digital';
        
        $emailService->setFrom($fromEmail, $appName);
        $emailService->setTo($email);
        $emailService->setSubject('Reset Password - ' . $appName);

        $resetLink = base_url() . '?reset_token=' . $token;
        
        $message = "
        <h3>Halo {$user['nama']},</h3>
        <p>Anda telah meminta untuk mereset password akun Anda di {$appName}.</p>
        <p>Silakan klik tautan di bawah ini untuk membuat password baru:</p>
        <p><a href='{$resetLink}' style='padding: 10px 15px; background: #E11D48; color: #fff; text-decoration: none; border-radius: 5px;'>Reset Password</a></p>
        <p>Tautan ini akan kedaluwarsa dalam 1 jam.</p>
        <p>Jika Anda tidak meminta reset password, abaikan email ini.</p>
        ";

        $emailService->setMessage($message);

        if ($emailService->send()) {
            return $this->response->setJSON(['status' => 'success', 'message' => 'Tautan reset password telah dikirim ke email Anda']);
        } else {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Gagal mengirim email: ' . $emailService->printDebugger(['headers'])])->setStatusCode(500);
        }
    }

    public function resetPassword()
    {
        $token = $this->request->getVar('token');
        $newPassword = $this->request->getVar('password');

        if (empty($token) || empty($newPassword)) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Token dan password baru diperlukan'])->setStatusCode(400);
        }

        $userModel = new UserModel();
        $user = $userModel->where('reset_token', $token)->first();

        if (!$user) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Token reset tidak valid'])->setStatusCode(400);
        }

        if (strtotime($user['reset_expires_at']) < time()) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Token reset telah kedaluwarsa'])->setStatusCode(400);
        }

        $userModel->update($user['id'], [
            'password' => password_hash($newPassword, PASSWORD_BCRYPT),
            'reset_token' => null,
            'reset_expires_at' => null
        ]);

        return $this->response->setJSON(['status' => 'success', 'message' => 'Password berhasil diubah. Silakan login dengan password baru Anda.']);
    }
}
