<?php namespace App\Controllers;

use App\Models\UserModel;
use CodeIgniter\HTTP\RedirectResponse;
use Config\SocialAuth;
use Config\Services;

class Auth extends BaseController
{
	protected $userModel;
	protected $session;
	protected $socialConfig;

	public function __construct()
	{
		$this->userModel = new UserModel();
		$this->session = Services::session();
		$this->socialConfig = config('SocialAuth');
	}

	public function login()
	{
		if ($this->session->get('isLoggedIn')) {
			return redirect()->to('/admin/news');
		}

		$data = [
			'title'       => 'Login - Portal Berita Produksi',
			'validation'  => Services::validation(),
			'socialReady' => $this->isSocialConfigured(),
		];

		return view('auth/login', $data);
	}

	public function processLogin()
	{
		$validation = Services::validation();
		$validation->setRules([
			'username' => [
				'label'  => 'Username',
				'rules'  => 'required|min_length[3]',
				'errors' => [
					'required'   => 'Username harus diisi',
					'min_length' => 'Username minimal 3 karakter',
				],
			],
			'password' => [
				'label'  => 'Password',
				'rules'  => 'required|min_length[3]',
				'errors' => [
					'required'   => 'Password harus diisi',
					'min_length' => 'Password minimal 3 karakter',
				],
			],
		]);

		if (!$validation->withRequest($this->request)->run()) {
			return redirect()->back()->withInput()->with('errors', $validation->getErrors());
		}

		$username = $this->request->getPost('username');
		$password = $this->request->getPost('password');
		$remember = (bool) $this->request->getPost('remember');

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

		if (!$user || !$this->userModel->verifyPassword($password, $user['password'])) {
			return redirect()->back()
				->withInput()
				->with('error', 'Username atau password salah');
		}

		if ($user['role'] !== 'admin') {
			return redirect()->back()
				->withInput()
				->with('error', 'Hanya admin yang dapat mengakses halaman ini');
		}

		return $this->completeLogin($user, $remember, 'Selamat datang, ' . $user['name'] . '!');
	}

	public function logout()
	{
		$this->session->destroy();
		$this->response->deleteCookie('remember_token');

		return redirect()->to('/login')->with('success', 'Anda telah berhasil logout');
	}

	// -------- Google Login ----------
	public function redirectToGoogle()
	{
		if (!$this->isSocialConfigured('google')) {
			return redirect()->to('/login')->with('error', 'Google Login belum dikonfigurasi.');
		}

		$state = bin2hex(random_bytes(16));
		$this->session->set('oauth_google_state', $state);

		$params = http_build_query([
			'client_id'     => $this->socialConfig->googleClientId,
			'redirect_uri'  => $this->socialConfig->googleRedirectUri,
			'response_type' => 'code',
			'scope'         => 'openid email profile',
			'access_type'   => 'offline',
			'prompt'        => 'consent',
			'state'         => $state,
		]);

		return redirect()->to('https://accounts.google.com/o/oauth2/v2/auth?' . $params);
	}

	public function handleGoogleCallback()
	{
		if ($error = $this->request->getGet('error')) {
			return redirect()->to('/login')->with('error', 'Google Login gagal: ' . $error);
		}

		if (!$this->validateState('google', $this->request->getGet('state'))) {
			return redirect()->to('/login')->with('error', 'Google Login tidak valid (state).');
		}

		$code = $this->request->getGet('code');
		if (!$code) {
			return redirect()->to('/login')->with('error', 'Kode Google tidak ditemukan.');
		}

		$token = $this->exchangeToken(
			'https://oauth2.googleapis.com/token',
			[
				'code'          => $code,
				'client_id'     => $this->socialConfig->googleClientId,
				'client_secret' => $this->socialConfig->googleClientSecret,
				'redirect_uri'  => $this->socialConfig->googleRedirectUri,
				'grant_type'    => 'authorization_code',
			]
		);

		if (!$token || !isset($token['access_token'])) {
			return redirect()->to('/login')->with('error', 'Gagal mendapatkan token Google.');
		}

		$userInfo = $this->fetchJson(
			'https://www.googleapis.com/oauth2/v3/userinfo',
			['Authorization' => 'Bearer ' . $token['access_token']]
		);

		if (!$userInfo) {
			return redirect()->to('/login')->with('error', 'Tidak dapat membaca profil Google.');
		}

		return $this->loginSocialUser('google', [
			'email'       => $userInfo['email'] ?? null,
			'name'        => $userInfo['name'] ?? ($userInfo['given_name'] ?? 'Google User'),
			'provider_id' => $userInfo['sub'] ?? '',
			'avatar'      => $userInfo['picture'] ?? null,
		]);
	}

	// -------- Facebook Login ----------
	public function redirectToFacebook()
	{
		if (!$this->isSocialConfigured('facebook')) {
			return redirect()->to('/login')->with('error', 'Facebook Login belum dikonfigurasi.');
		}

		$state = bin2hex(random_bytes(16));
		$this->session->set('oauth_facebook_state', $state);

		$params = http_build_query([
			'client_id'     => $this->socialConfig->facebookClientId,
			'redirect_uri'  => $this->socialConfig->facebookRedirectUri,
			'state'         => $state,
			'scope'         => 'email,public_profile',
			'response_type' => 'code',
		]);

		return redirect()->to('https://www.facebook.com/v17.0/dialog/oauth?' . $params);
	}

	public function handleFacebookCallback()
	{
		if ($error = $this->request->getGet('error')) {
			return redirect()->to('/login')->with('error', 'Facebook Login gagal: ' . $error);
		}

		if (!$this->validateState('facebook', $this->request->getGet('state'))) {
			return redirect()->to('/login')->with('error', 'Facebook Login tidak valid (state).');
		}

		$code = $this->request->getGet('code');
		if (!$code) {
			return redirect()->to('/login')->with('error', 'Kode Facebook tidak ditemukan.');
		}

		$tokenParams = [
			'client_id'     => $this->socialConfig->facebookClientId,
			'redirect_uri'  => $this->socialConfig->facebookRedirectUri,
			'client_secret' => $this->socialConfig->facebookClientSecret,
			'code'          => $code,
		];

		$token = $this->fetchJson('https://graph.facebook.com/v17.0/oauth/access_token?' . http_build_query($tokenParams));

		if (!$token || !isset($token['access_token'])) {
			return redirect()->to('/login')->with('error', 'Gagal mendapatkan token Facebook.');
		}

		$userInfo = $this->fetchJson('https://graph.facebook.com/me?fields=id,name,email,picture.type(large)&access_token=' . $token['access_token']);

		if (!$userInfo) {
			return redirect()->to('/login')->with('error', 'Tidak dapat membaca profil Facebook.');
		}

		if (empty($userInfo['email'])) {
			return redirect()->to('/login')->with('error', 'Email Facebook tidak ditemukan. Pastikan Anda memberikan akses email.');
		}

		return $this->loginSocialUser('facebook', [
			'email'       => $userInfo['email'],
			'name'        => $userInfo['name'] ?? 'Facebook User',
			'provider_id' => $userInfo['id'],
			'avatar'      => $userInfo['picture']['data']['url'] ?? null,
		]);
	}

	// -------- Helper Methods ----------
	protected function completeLogin(array $user, bool $remember = false, string $message = 'Login berhasil')
	{
		$this->session->set([
			'isLoggedIn' => true,
			'userId'     => $user['id'],
			'username'   => $user['username'],
			'name'       => $user['name'],
			'role'       => $user['role'],
		]);

		if ($remember) {
			$this->response->setCookie([
				'name'     => 'remember_token',
				'value'    => bin2hex(random_bytes(32)),
				'expire'   => 86400 * 30,
				'path'     => '/',
				'secure'   => false,
				'httponly' => true,
			]);
		}

		return redirect()->to('/admin/news')->with('success', $message);
	}

	protected function loginSocialUser(string $provider, array $profile)
	{
		if (empty($profile['email'])) {
			return redirect()->to('/login')->with('error', ucfirst($provider) . ' tidak mengembalikan email.');
		}

		// Jika user sudah ada
		$user = $this->userModel->findByEmail($profile['email']);

		$allowed = $this->socialConfig->allowedEmails ?? [];
		if (!$user && !empty($allowed) && !in_array($profile['email'], $allowed, true)) {
			return redirect()->to('/login')->with('error', 'Email ini belum terdaftar sebagai admin.');
		}

		if (!$user) {
			$username = $this->generateUniqueUsername($profile['email']);
			$userId   = $this->userModel->insert([
				'username'    => $username,
				'password'    => bin2hex(random_bytes(16)),
				'name'        => $profile['name'],
				'email'       => $profile['email'],
				'role'        => 'admin',
				'provider'    => $provider,
				'provider_id' => $profile['provider_id'],
				'avatar'      => $profile['avatar'] ?? null,
			]);

			$user = $this->userModel->find($userId);
		} else {
			$this->userModel->update($user['id'], [
				'provider'    => $provider,
				'provider_id' => $profile['provider_id'],
				'avatar'      => $profile['avatar'] ?? $user['avatar'],
			]);

			$user = $this->userModel->find($user['id']);
		}

		return $this->completeLogin($user, false, 'Selamat datang kembali, ' . $user['name'] . '!');
	}

	protected function generateUniqueUsername(string $email): string
	{
		$base = preg_replace('/[^a-z0-9]+/i', '', strstr($email, '@', true) ?: $email);
		$username = $base ?: 'user' . random_int(1000, 9999);
		$suffix = 1;

		while ($this->userModel->where('username', $username)->first()) {
			$username = $base . $suffix;
			$suffix++;
		}

		return strtolower($username);
	}

	protected function exchangeToken(string $url, array $formParams): ?array
	{
		try {
			$client = Services::curlrequest([
				'headers' => [
					'Accept' => 'application/json',
				],
			]);

			$response = $client->post($url, ['form_params' => $formParams]);

			return json_decode($response->getBody(), true);
		} catch (\Throwable $th) {
			log_message('error', 'Token exchange error: ' . $th->getMessage());
			return null;
		}
	}

	protected function fetchJson(string $url, array $headers = []): ?array
	{
		try {
			$client = Services::curlrequest([
				'headers' => array_merge(['Accept' => 'application/json'], $headers),
			]);

			$response = $client->get($url);
			return json_decode($response->getBody(), true);
		} catch (\Throwable $th) {
			log_message('error', 'Fetch JSON error: ' . $th->getMessage());
			return null;
		}
	}

	protected function validateState(string $provider, ?string $state): bool
	{
		$sessionKey = 'oauth_' . $provider . '_state';
		$savedState = $this->session->get($sessionKey);
		$this->session->remove($sessionKey);

		return $state && $savedState && hash_equals($savedState, $state);
	}

	protected function isSocialConfigured(?string $provider = null): bool
	{
		if ($provider === 'google') {
			return !str_contains($this->socialConfig->googleClientId, 'YOUR_GOOGLE_CLIENT_ID');
		}

		if ($provider === 'facebook') {
			return !str_contains($this->socialConfig->facebookClientId, 'YOUR_FACEBOOK_APP_ID');
		}

		return $this->isSocialConfigured('google') || $this->isSocialConfigured('facebook');
	}
}
