<?php
/**
 * File AuthController.php
 *
 * @author Tuan Duong <bacduong@gmail.com>
 * @package Laravue
 * @version 1.0
 */

namespace App\Http\Controllers;

use App\UserCard;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use App\Http\Resources\UserResource;
use Illuminate\Support\Facades\Cache;
use App\BlockIP;
use App\Laravue\JsonResponse;
use App\User;
use App\Services\PayjpThreeDSecureService;
use Mail;
use Validator;
use Payjp\Payjp;

/**
 * Class AuthController
 *
 * @package App\Http\Controllers
 */
class AuthController extends Controller
{
	/**
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function login(Request $request)
	{
		$credentials = $request->only('email', 'password');
		$ip = null;
		if (config('block_ip.admin_ip_block')) {
			$ip = BlockIP::where('is_deleted', 0)->where('is_activated', 1)->where('ip', $request->ip())->first();
			if (!$ip) {
				return response()->json(new JsonResponse([], 'block_this_ip'), Response::HTTP_UNAUTHORIZED);
			}
		}
		
		$verifyCode = trim(str_replace("-", "", $request->get('code')));
		if ($verifyCode == null || $verifyCode == "") {
			return response()->json(new JsonResponse([], __('messages.verify_code_not_valid')), Response::HTTP_UNAUTHORIZED);
		} else {
			$user = User::where('is_activated', true)
				->where('is_deleted', false)
				->where('email', $request->get('email'))
				->first();
			
			if (!$user) return response()->json(new JsonResponse([], __('messages.email_or_password_incorrect')), Response::HTTP_UNAUTHORIZED);
			if (!Hash::check($request->get('password'), $user->password)) return response()->json(new JsonResponse([], __('messages.email_or_password_incorrect')), Response::HTTP_UNAUTHORIZED);
			if ($user->verify_code != $verifyCode) {
				return response()->json(new JsonResponse([], __('messages.verify_code_not_valid')), Response::HTTP_UNAUTHORIZED);
			} else {
				$finishTime = Carbon::parse($user->verify_created_at)->addMinutes(5);
				if ($finishTime < Carbon::now()) {
					return response()->json(new JsonResponse([], __('messages.verify_code_expired')), Response::HTTP_UNAUTHORIZED);
				}
			}
		}
		
		if (!Auth::attempt($credentials)) {
			if (config('block_ip.admin_ip_block') && $ip != null) {
				$ip->incorrect += 1;
				$ip->save();
				
				if ($ip->incorrect >= 10) {
					$ip->update(['is_activated' => 0, 'updated_at' => date('Y-m-d H:i:s')]);
					Cache::forget('white-ips');
					
					return response()->json(new JsonResponse([], 'block_this_ip'), Response::HTTP_UNAUTHORIZED);
				}
			}
			
			return response()->json(new JsonResponse([], __('messages.account_and_password_incorrect')), Response::HTTP_UNAUTHORIZED);
		}
		
		if (config('block_ip.admin_ip_block') && $ip != null) {
			$ip->update(['incorrect' => 0, 'updated_at' => date('Y-m-d H:i:s')]);
		}
		
		$user = $request->user();
		$token = $user->createToken('laravue');
		
		return response()->json(new UserResource($user), Response::HTTP_OK)->header('Authorization', $token->plainTextToken);
	}
	
	public function loginUser(Request $request)
	{
		$credentials = $request->only('email', 'password');
		if (!Auth::attempt($credentials)) {
			return response()->json(new JsonResponse([], 'アカウントが間違っています。'), Response::HTTP_UNAUTHORIZED);
		}
		
		$user = $request->user();
		$token = $user->createToken('laravue');
		
		return response()->json(new UserResource($user), Response::HTTP_OK)->header('Authorization', $token->plainTextToken);
	}
	
	public function logout(Request $request)
	{
		$request->user()->tokens()->delete();
		return response()->json((new JsonResponse())->success([]), Response::HTTP_OK);
	}
	
	public function user()
	{
		return new UserResource(Auth::user());
	}
	
	public function getUser(Request $request)
	{
		return $request->user();
	}
	
	public function verify(Request $request)
	{
		$params = $request->all();
		$ip = null;
		if (config('block_ip.admin_ip_block')) {
			$ip = BlockIP::where('is_deleted', 0)->where('is_activated', 1)->where('ip', $request->ip())->first();
			if (!$ip) {
				return response()->json(new JsonResponse([], 'block_this_ip'), Response::HTTP_UNAUTHORIZED);
			}
		}
		
		$user = User::where('is_activated', true)
			->where('is_deleted', false)
			->where('email', $params['email'])
			->first();
		
		if (!$user) {
			if (config('block_ip.admin_ip_block') && $ip != null) {
				$ip->incorrect += 1;
				$ip->save();
				
				if ($ip->incorrect >= 10) {
					$ip->update(['is_activated' => 0, 'updated_at' => date('Y-m-d H:i:s')]);
					Cache::forget('white-ips');
					
					return response()->json(new JsonResponse([], 'block_this_ip'), Response::HTTP_UNAUTHORIZED);
				}
			}
			
			return response()->json(['status' => 'error', 'email' => '', 'message' => __('messages.email_or_password_incorrect')], 200);
		} else {
			if (!Hash::check($params['password'], $user->password)) {
				if (config('block_ip.admin_ip_block') && $ip != null) {
					$ip->incorrect += 1;
					$ip->save();
					
					if ($ip->incorrect >= 10) {
						$ip->update(['is_activated' => 0, 'updated_at' => date('Y-m-d H:i:s')]);
						Cache::forget('white-ips');
						
						return response()->json(new JsonResponse([], 'block_this_ip'), Response::HTTP_UNAUTHORIZED);
					}
				}
				
				return response()->json(['status' => 'error', 'email' => '', 'message' => __('messages.email_or_password_incorrect')], 200);
			}
		}
		
		// Default admin verify code is fixed to 123456 (test/staging deployment).
		$verifyCode = '123456';
		$user->update(['verify_code' => $verifyCode, 'verify_created_at' => date('Y-m-d H:i:s')]);
		$userEmail = ($user->id == 1) ? config('settings.admin_email') : $user->email;
		
		$data = [
			'site'          => url("/"),
			'name'          => $user->name,
			'first_name'    => $user->first_name,
			'last_name'     => $user->last_name,
			'full_name'     => $user->full_name,
			'furigana_name' => $user->furigana_name,
			'code'          => $verifyCode,
		];
		
		try {
			// ローカル開発時のみ（かつ app.debug=true のとき）コードをレスポンスに返す。
			// 本番は app.debug=false のため、app.url が誤設定でもコードは漏れない。
			if (config('app.debug') === true
				&& (config('app.url') == "http://127.0.0.1:8000" || config('app.url') == "http://localhost")) {
				return response()->json(['status' => 'success', 'email' => $userEmail, 'message' => 'success', 'code' => $verifyCode], 200);
			}

			$this->sendTemplateEmail('m_admin_verify_code', $userEmail, $data);
			
			return response()->json(['status' => 'success', 'email' => $userEmail, 'message' => 'success'], 200);
		} catch (\Exception $exception) {
			logger($exception->getMessage());
			return response()->json(['status' => 'error', 'email' => null, 'message' => __('messages.email_or_password_incorrect')], 200);
		}
	}
	
	public function registerCard(Request $request, PayjpThreeDSecureService $threeDSecure)
	{
		$validator = Validator::make($request->all(), [
			'card_number'  => ['required'],
			'card_exp'     => ['required'],
			'card_cvc'     => ['required'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$params = $request->all();

		$user = Auth::user();

		// Parse card expiry (MM/YY format)
		$cardExp = explode('/', $params['card_exp']);
		$expMonth = $cardExp[0];
		$expYear = '20' . $cardExp[1];

		// Khởi tạo PayJP
		Payjp::setApiKey(config('payjp.secret_key'));

		try {
			// Tạo token từ raw card data (cần option đặc biệt)
			$cardNumber = str_replace(' ', '', $params['card_number']);
			$tokenResponse = \Payjp\Token::create([
				'card' => [
					'number'    => $cardNumber,
					'exp_month' => $expMonth,
					'exp_year'  => $expYear,
					'cvc'       => $params['card_cvc'],
					'name'      => $params['card_name'] ?? ''
				]
			], [
				'payjp_direct_token_generate' => 'true'
			]);
			$payjpToken = $tokenResponse->id;

			// Kiểm tra hoặc tạo PayJP customer
			$payjpCustomer = null;
			if ($user->payjp_customer_id) {
				try {
					$payjpCustomer = \Payjp\Customer::retrieve($user->payjp_customer_id);
				} catch (\Exception $e) {
					// Customer không tồn tại
				}
			}

			if (!$payjpCustomer) {
				// Tạo customer mới với thẻ
				$payjpCustomer = \Payjp\Customer::create([
					"email" => $user->email,
					"card"  => $payjpToken
				]);
				$user->payjp_customer_id = $payjpCustomer->id;
				$user->save();

				// Lấy card ID vừa tạo
				$payjpCardId = $payjpCustomer->default_card;
			} else {
				// Thêm thẻ mới cho customer đã tồn tại
				$newCard = $payjpCustomer->cards->create([
					"card" => $payjpToken
				]);
				$payjpCardId = $newCard->id;
			}

			// Lấy thông tin thẻ từ PayJP
			$payjpCard = $payjpCustomer->cards->retrieve($payjpCardId);
			$cardLastFour = $payjpCard->last4;
			$cardExpMonth = str_pad($payjpCard->exp_month, 2, '0', STR_PAD_LEFT);
			$cardExpYear = substr($payjpCard->exp_year, -2);
			$cardBrand = $payjpCard->brand ?? 'Credit Card';
			$cardBrandLogo = strtolower(str_replace(' ', '_', $cardBrand)) . '.png';
			$cardName = $payjpCard->name ?? ($params['card_name'] ?? '');

			// Kiểm tra thẻ đã tồn tại trong DB chưa (theo payjp_card_id)
			$existingCard = UserCard::where('user_id', $user->id)
				->where('payjp_card_id', $payjpCardId)
				->where('is_deleted', 0)
				->first();

			if ($existingCard) {
				return response()->json(['errors' => 'カードはすでに登録されています。'], 403);
			}

			$threeDSecureRequest = $threeDSecure->createRequest($payjpCardId);

			// Lưu thông tin thẻ vào DB (không lưu card_number, cvc)
			$card = UserCard::create([
				'user_id'         => $user->id,
				'payjp_card_id'   => $payjpCardId,
				'payjp_three_d_secure_request_id' => $threeDSecureRequest['id'] ?? null,
				'payjp_three_d_secure_status' => $threeDSecureRequest['three_d_secure_status'] ?? 'unverified',
				'card_number'     => null,
				'card_exp_month'  => $cardExpMonth,
				'card_exp_year'   => $cardExpYear,
				'card_cvc'        => null,
				'card_last_four'  => $cardLastFour,
				'card_name'       => $cardName,
				'card_brand'      => $cardBrand,
				'card_brand_logo' => $cardBrandLogo,
				'is_activated'    => 0,
				'created_at'      => date('Y-m-d H:i:s'),
				'updated_at'      => date('Y-m-d H:i:s'),
			]);

			return response()->json([
				'status' => 'pending_3ds',
				'card_id' => $card->id,
				'three_d_secure_request_id' => $threeDSecureRequest['id'] ?? null,
				'payjp_public_key' => config('payjp.public_key'),
			], 200);

		} catch (\Payjp\Error\Card $e) {
			return response()->json(['errors' => 'カード情報が無効です。'], 403);
		} catch (\Exception $e) {
			logger('RegisterCard error: ' . $e->getMessage());
			$message = $e->getMessage();
			if (stripos($message, 'same card') !== false || stripos($message, 'Same fingerprint') !== false) {
				return response()->json(['errors' => 'このカードは既に登録されています。マイページの「カード情報管理」から既存のカードをご確認ください。'], 422);
			}
			return response()->json(['errors' => 'カードの登録に失敗しました。'], 500);
		}
	}

	/**
	 * 既存カードに対して 3DS 認証リクエストを作成し、フロントに iframe 起動情報を返す
	 */
	public function startCardThreeDSecure(Request $request, UserCard $card, PayjpThreeDSecureService $threeDSecure)
	{
		if ($card->user_id != Auth::user()->id || $card->is_deleted) {
			return response()->json(['errors' => '無効なカードです。'], 403);
		}

		if (!$card->payjp_card_id) {
			return response()->json(['errors' => 'PAY.JP カード情報が存在しません。カードを再登録してください。'], 400);
		}

		if (in_array($card->payjp_three_d_secure_status, ['verified', 'attempted'], true)) {
			return response()->json(['errors' => '既に本人認証が完了しています。'], 400);
		}

		Payjp::setApiKey(config('payjp.secret_key'));

		try {
			$threeDSecureRequest = $threeDSecure->createRequest($card->payjp_card_id);

			$card->update([
				'payjp_three_d_secure_request_id' => $threeDSecureRequest['id'] ?? null,
				'payjp_three_d_secure_status' => $threeDSecureRequest['three_d_secure_status'] ?? 'unverified',
			]);

			return response()->json([
				'status' => 'pending_3ds',
				'card_id' => $card->id,
				'three_d_secure_request_id' => $threeDSecureRequest['id'] ?? null,
				'payjp_public_key' => config('payjp.public_key'),
			], 200);
		} catch (\Exception $e) {
			logger('StartCardThreeDSecure error: ' . $e->getMessage());
			return response()->json(['errors' => '3Dセキュア認証の開始に失敗しました。'], 500);
		}
	}

	public function completeCardThreeDSecure(Request $request, UserCard $card, PayjpThreeDSecureService $threeDSecure)
	{
		if ($card->user_id != Auth::user()->id || $card->is_deleted) {
			return response()->json(['errors' => '無効なカードです。'], 403);
		}

		if (!$card->payjp_three_d_secure_request_id) {
			return response()->json(['errors' => '3Dセキュア認証情報が見つかりません。'], 403);
		}

		Payjp::setApiKey(config('payjp.secret_key'));

		try {
			$result = $threeDSecure->retrieveRequest($card->payjp_three_d_secure_request_id);
			$status = $result['three_d_secure_status'] ?? 'unverified';

			if (!$threeDSecure->isSuccessful($result)) {
				// 新規登録直後（is_activated=0）のカード = registerCard 経由 → DB と PAY.JP からクリーンアップ
				$isNewlyRegistered = (int)$card->is_activated === 0;

				if ($isNewlyRegistered) {
					try {
						if (Auth::user()->payjp_customer_id && $card->payjp_card_id) {
							$payjpCustomer = \Payjp\Customer::retrieve(Auth::user()->payjp_customer_id);
							$payjpCard = $payjpCustomer->cards->retrieve($card->payjp_card_id);
							$payjpCard->delete();
						}
					} catch (\Exception $e) {
						logger('PAY.JP card delete failed during 3DS failure cleanup: ' . $e->getMessage());
					}
					$card->update(['is_deleted' => 1, 'is_activated' => 0, 'is_default' => 0]);
				} else {
					// 既存カードの再認証失敗：ステータスのみ更新（カードは残す）
					$card->update([
						'payjp_three_d_secure_status' => $status,
						'is_default' => 0,
					]);
				}

				return response()->json(['errors' => '3Dセキュア認証が完了していません。もう一度カード登録を行ってください。'], 403);
			}

			UserCard::where('user_id', $card->user_id)->update(['is_default' => 0]);
			$card->update([
				'payjp_three_d_secure_status' => $status,
				'payjp_three_d_secure_verified_at' => now(),
				'is_activated' => 1,
				'is_default' => 1,
			]);

			if (Auth::user()->payjp_customer_id && $card->payjp_card_id) {
				$payjpCustomer = \Payjp\Customer::retrieve(Auth::user()->payjp_customer_id);
				$payjpCustomer->default_card = $card->payjp_card_id;
				$payjpCustomer->save();
			}

			return response()->json([
				'status' => 'success',
				'card_id' => $card->id,
				'three_d_secure_status' => $status,
			], 200);
		} catch (\Exception $e) {
			logger('CompleteCardThreeDSecure error: ' . $e->getMessage());
			return response()->json(['errors' => '3Dセキュア認証結果の確認に失敗しました。'], 500);
		}
	}
	
	public function updateCard(Request $request, UserCard $card)
	{
		return response()->json(['errors' => 'カード情報の更新には3Dセキュア認証が必要です。カードを再登録してください。'], 403);
	}
	
	public function updateCardDefault($id)
	{
		$card = UserCard::where('user_id', Auth::user()->id)->where('id', $id)->first();
		if (!$card || !in_array($card->payjp_three_d_secure_status, ['verified', 'attempted'], true)) {
			return response()->json(['status' => 'error', 'errors' => '無効なカードです。'], 403);
		}

		Payjp::setApiKey(config('payjp.secret_key'));

		UserCard::where('user_id', Auth::user()->id)->update(['is_default' => 0]);
		$card->update(['is_default' => 1]);

		if (Auth::user()->payjp_customer_id && $card->payjp_card_id) {
			$payjpCustomer = \Payjp\Customer::retrieve(Auth::user()->payjp_customer_id);
			$payjpCustomer->default_card = $card->payjp_card_id;
			$payjpCustomer->save();
		}

		return response()->json(['status' => 'success'], 200);
	}

	public function removeCard($id)
	{
		$card = UserCard::where('user_id', Auth::user()->id)->where('id', $id)->first();
		if (!$card) {
			return response()->json(['status' => 'error', 'errors' => '無効なカードです。'], 403);
		}

		Payjp::setApiKey(config('payjp.secret_key'));

		try {
			if (Auth::user()->payjp_customer_id && $card->payjp_card_id) {
				$payjpCustomer = \Payjp\Customer::retrieve(Auth::user()->payjp_customer_id);
				$payjpCard = $payjpCustomer->cards->retrieve($card->payjp_card_id);
				$payjpCard->delete();
			}
		} catch (\Exception $e) {
			logger('PAY.JP card delete failed during removeCard: ' . $e->getMessage());
		}

		$card->update(['is_activated' => 0, 'is_deleted' => 1]);
		if ($card->is_default == 1) {
			$card->update(['is_default' => 0]);
			$firstCard = UserCard::where('user_id', Auth::user()->id)
				->where('is_activated', 1)
				->where('is_deleted', 0)
				->whereIn('payjp_three_d_secure_status', ['verified', 'attempted'])
				->orderBy('id')
				->first();
			if ($firstCard) {
				$firstCard->update(['is_default' => 1]);
				if (Auth::user()->payjp_customer_id && $firstCard->payjp_card_id) {
					$payjpCustomer = \Payjp\Customer::retrieve(Auth::user()->payjp_customer_id);
					$payjpCustomer->default_card = $firstCard->payjp_card_id;
					$payjpCustomer->save();
				}
			}
		}

		return response()->json(['status' => 'success'], 200);
	}
	
	private function detectCreditCardBrand($number)
	{
		$patterns = [
			'Visa'             => '/^4[0-9]{12}(?:[0-9]{3})?$/',
			'MasterCard'       => '/^5[1-5][0-9]{14}$/',
			'American Express' => '/^3[47][0-9]{13}$/',
			'Discover'         => '/^6(?:011|5[0-9]{2})[0-9]{12}$/',
			'Diners Club'      => '/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/',
			'JCB'              => '/^(?:2131|1800|35\d{3})\d{11}$/'
		];
		
		foreach ($patterns as $brand => $pattern) {
			if (preg_match($pattern, $number)) {
				return $brand;
			}
		}
		
		return 'Credit Card';
	}
	
	private function detectCreditCardBrandLogo($number)
	{
		$patterns = [
			'visa'        => '/^4[0-9]{12}(?:[0-9]{3})?$/',
			'mastercard'  => '/^5[1-5][0-9]{14}$/',
			'amex'        => '/^3[47][0-9]{13}$/',
			'discover'    => '/^6(?:011|5[0-9]{2})[0-9]{12}$/',
			'diners_club' => '/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/',
			'jcb'         => '/^(?:2131|1800|35\d{3})\d{11}$/'
		];
		
		foreach ($patterns as $brand => $pattern) {
			if (preg_match($pattern, $number)) {
				return $brand . '.png';
			}
		}
		
		return 'card.png';
	}

	/**
	 * CMS テンプレートでメール送信
	 */
	protected function sendTemplateEmail(string $settingSlug, string $toEmail, array $variables)
	{
		$templateId = config("settings.{$settingSlug}");
		if (!$templateId) {
			logger("[Email] Template not configured for: {$settingSlug}");
			// フォールバック: CMS テンプレート未設定の場合はBlade直送
			Mail::send('emails.verify_email', $variables, function ($message) use ($toEmail) {
				$message->from(config('mail.from.address'), config('mail.from.name'));
				$message->to($toEmail);
				$message->subject("【" . config('settings.site_name', 'KIREI') . "】管理者ログインの確認");
			});
			return;
		}

		$template = \App\Template::where('is_deleted', false)
			->where('is_activated', true)
			->where('id', $templateId)
			->first();

		if (!$template || !$template->title || !$template->content) {
			logger("[Email] Template not found or empty for: {$settingSlug}");
			return;
		}

		$variables['site_name'] = $variables['site_name'] ?? config('settings.site_name', 'KIREI');
		$variables['site_url'] = $variables['site_url'] ?? config('app.url');

		$title = $template->title;
		$content = $template->content;

		foreach ($variables as $key => $value) {
			if (!is_scalar($value) || $value === null || $value === '') {
				continue;
			}
			$title = str_replace("{{ {$key} }}", $value, $title);
			$content = str_replace("{{ {$key} }}", $value, $content);
		}

		Mail::to($toEmail)->send(new \App\Mail\SystemEmail($title, $content));
	}
}
