<?php

namespace App\Services;

use App\Laravue\Models\User;
use App\Order;
use App\IdentityVerificationLog;
use App\Mail\IdentityVerificationApproved;
use App\Mail\IdentityVerificationApprovedWithOrders;
use App\Mail\IdentityVerificationRejected;
use App\Mail\ProvisionalOrderCancelled;
use App\Mail\ProvisionalOrderConfirmed;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Carbon\Carbon;

class IdentityVerificationService
{
	/**
	 * Default expiration days for provisional reservation
	 */
	const PROVISIONAL_EXPIRATION_DAYS = 3;
	
	/**
	 * Resubmission expiration days after rejection
	 */
	const RESUBMISSION_EXPIRATION_DAYS = 2;
	
	/**
	 * Maximum rejection count before permanent cancellation
	 */
	const MAX_REJECTION_COUNT = 2;
	
	/**
	 * Storage disk for identity documents
	 */
	const STORAGE_DISK = 'public';
	
	/**
	 * Storage path for identity documents
	 */
	const STORAGE_PATH = 'identity_documents';
	
	/**
	 * Submit identity documents for verification
	 *
	 * @param mixed $user
	 * @param string $documentType
	 * @param array $files
	 * @param Order|null $order
	 * @param string|null $ipAddress
	 * @param string|null $userAgent
	 * @return array
	 * @throws \Exception
	 */
	public function submitDocuments(
		$user,
		string $documentType,
		array $files,
		?Order $order = null,
		?string $ipAddress = null,
		?string $userAgent = null
	): array
	{
		// Validate document type
		if (!in_array($documentType, [User::IDENTITY_DOC_DRIVER_LICENSE, User::IDENTITY_DOC_MY_NUMBER_CARD])) {
			throw new \InvalidArgumentException('Invalid document type');
		}
		
		// Check if user can submit
		if ($user->isIdentityVerified()) {
			throw new \Exception('Identity already verified');
		}
		
		if ($user->isIdentityPending()) {
			throw new \Exception('Identity verification is already pending');
		}
		
		// Validate required files based on document type
		$this->validateDocumentFiles($documentType, $files);
		
		return DB::transaction(function () use ($user, $documentType, $files, $order, $ipAddress, $userAgent) {
			$statusBefore = $user->identity_status;
			$isResubmission = $user->isIdentityRejected();
			
			// Upload files
			$uploadedPaths = $this->uploadDocumentFiles($user, $documentType, $files);
			
			// Update user
			$user->update([
				'identity_status'           => User::IDENTITY_STATUS_PENDING,
				'identity_submitted_at'     => now(),
				'identity_document_type'    => $documentType,
				'driver_license_front'      => $uploadedPaths['driver_license_front'] ?? null,
				'driver_license_back'       => $uploadedPaths['driver_license_back'] ?? null,
				'my_number_card_front'      => $uploadedPaths['my_number_card_front'] ?? null,
				'identity_rejected_at'      => null,
				'identity_rejection_reason' => null,
			]);
			
			// Create log entry
			if ($isResubmission) {
				IdentityVerificationLog::logResubmission(
					$user,
					$order,
					$documentType,
					$uploadedPaths,
					$ipAddress,
					$userAgent
				);
			} else {
				IdentityVerificationLog::logSubmission(
					$user,
					$order,
					$documentType,
					$uploadedPaths,
					$ipAddress,
					$userAgent
				);
			}
			
			// Update order provisional expiration if applicable
			if ($order && $order->isProvisional()) {
				// Reset expiration to give more time for review
				$order->update([
					'provisional_expires_at' => now()->addDays(self::PROVISIONAL_EXPIRATION_DAYS),
				]);
			}
			
			return [
				'success' => true,
				'message' => $isResubmission ? '本人確認書類を再提出しました' : '本人確認書類を提出しました',
				'status'  => User::IDENTITY_STATUS_PENDING,
			];
		});
	}
	
	/**
	 * Approve identity verification
	 *
	 * @param User $user
	 * @param User $admin
	 * @param string|null $notes
	 * @return array
	 * @throws \Exception
	 */
	public function approve($user, $admin, ?string $notes = null): array
	{
		if (!$user->isIdentityPending()) {
			throw new \Exception('User identity is not pending verification');
		}
		
		return DB::transaction(function () use ($user, $admin, $notes) {
			// Update user
			$user->update([
				'identity_status'      => User::IDENTITY_STATUS_APPROVED,
				'identity_approved_at' => now(),
			]);
			
			// Create log entry
			IdentityVerificationLog::logApproval($user, $admin, $notes);
			
			// Xử lý tất cả provisional orders và thu thập kết quả
			$confirmResults = $this->confirmProvisionalOrders($user);
			
			// Lấy danh sách orders đã xử lý để gửi trong email
			$orders = Order::where('user_id', $user->id)
				->whereIn('id', collect($confirmResults['orders'])->pluck('order_id'))
				->with(['order_detail.product', 'delivery'])
				->get();
			
			// Gửi 1 EMAIL DUY NHẤT chứa tất cả orders (theo yêu cầu Feedback #2)
			if ($orders->isNotEmpty()) {
				Mail::to($user->email)->send(
					new IdentityVerificationApprovedWithOrders($user, $orders, $confirmResults['orders'])
				);
			}

			return [
				'success' => true,
				'message' => '本人確認を承認しました',
				'status'  => User::IDENTITY_STATUS_APPROVED,
				'orders_processed' => $confirmResults,
			];
		});
	}
	
	/**
	 * Reject identity verification
	 *
	 * @param User $user
	 * @param User $admin
	 * @param string $reason
	 * @param string|null $notes
	 * @return array
	 * @throws \Exception
	 */
	public function reject($user, $admin, string $reason, ?string $notes = null): array
	{
		if (!$user->isIdentityPending()) {
			throw new \Exception('User identity is not pending verification');
		}
		
		return DB::transaction(function () use ($user, $admin, $reason, $notes) {
			$newRejectionCount = $user->identity_rejection_count + 1;
			
			// Update user
			$user->update([
				'identity_status'           => User::IDENTITY_STATUS_REJECTED,
				'identity_rejected_at'      => now(),
				'identity_rejection_count'  => $newRejectionCount,
				'identity_rejection_reason' => $reason,
			]);
			
			// Create log entry
			IdentityVerificationLog::logRejection($user, $admin, $reason, $notes);
			
			// Update provisional orders expiration
			$this->updateProvisionalOrdersAfterRejection($user, $newRejectionCount);
			
			$canResubmit = $newRejectionCount < self::MAX_REJECTION_COUNT;
			
			// Send rejection email to user
			Mail::to($user->email)->send(new IdentityVerificationRejected($user, $reason, $canResubmit));
			
			return [
				'success'         => true,
				'message'         => '本人確認を却下しました',
				'status'          => User::IDENTITY_STATUS_REJECTED,
				'rejection_count' => $newRejectionCount,
				'can_resubmit'    => $canResubmit,
			];
		});
	}
	
	/**
	 * Create a provisional reservation order
	 *
	 * @param mixed $user
	 * @param array $orderData
	 * @return Order
	 */
	public function createProvisionalOrder($user, array $orderData): Order
	{
		$orderData['status'] = Order::STATUS_PROVISIONAL; // status = 9
		$orderData['provisional_created_at'] = now();
		$orderData['provisional_expires_at'] = now()->addDays(self::PROVISIONAL_EXPIRATION_DAYS);
		$orderData['identity_verification_required'] = !$user->isIdentityVerified();
		$orderData['user_id'] = $user->id;

		return Order::create($orderData);
	}
	
	/**
	 * Cancel expired provisional orders
	 *
	 * @return array
	 */
	public function cancelExpiredProvisionalOrders(): array
	{
		$expiredOrders = Order::expiredProvisional()->get();
		$cancelledCount = 0;
		$errors = [];
		
		foreach ($expiredOrders as $order) {
			try {
				$this->cancelProvisionalOrder($order, '本人確認書類の提出期限が過ぎたため、自動キャンセルされました');
				$cancelledCount++;
			} catch (\Exception $e) {
				$errors[] = [
					'order_id' => $order->id,
					'error'    => $e->getMessage(),
				];
			}
		}
		
		return [
			'cancelled_count' => $cancelledCount,
			'errors'          => $errors,
		];
	}
	
	/**
	 * Cancel a provisional order
	 *
	 * @param Order $order
	 * @param string $reason
	 * @return void
	 */
	public function cancelProvisionalOrder(Order $order, string $reason): void
	{
		DB::transaction(function () use ($order, $reason) {
			$order->update([
				'status'              => Order::STATUS_CANCELLED,
				'auto_cancelled'      => true,
				'auto_cancelled_at'   => now(),
				'cancellation_reason' => $reason,
			]);
			
			// Log the cancellation
			$user = User::find($order->user_id);
			if ($user) {
				IdentityVerificationLog::logAutoCancellation($user, $order, $reason);
				
				// Send cancellation email to user
				Mail::to($user->email)->send(new ProvisionalOrderCancelled($user, $order, $reason));
			}
			
			// TODO: Release reserved products
		});
	}
	
	/**
	 * Get identity verification status for a user
	 *
	 * @param mixed $user
	 * @return array
	 */
	public function getVerificationStatus($user): array
	{
		$status = [
			'status'              => $user->identity_status,
			'status_label'        => $user->getIdentityStatusLabel(),
			'is_verified'         => $user->isIdentityVerified(),
			'is_pending'          => $user->isIdentityPending(),
			'is_rejected'         => $user->isIdentityRejected(),
			'needs_submission'    => $user->needsIdentitySubmission(),
			'can_resubmit'        => $user->canResubmitIdentity(),
			'document_type'       => $user->identity_document_type,
			'document_type_label' => $user->getIdentityDocumentTypeLabel(),
			'submitted_at'        => $user->identity_submitted_at ? $user->identity_submitted_at->format('Y-m-d H:i:s') : null,
			'approved_at'         => $user->identity_approved_at ? $user->identity_approved_at->format('Y-m-d H:i:s') : null,
			'rejected_at'         => $user->identity_rejected_at ? $user->identity_rejected_at->format('Y-m-d H:i:s') : null,
			'rejection_count'     => $user->identity_rejection_count,
			'rejection_reason'    => $user->identity_rejection_reason,
		];
		
		// Add document URLs if available
		if ($user->driver_license_front) {
			$status['driver_license_front_url'] = Storage::disk(self::STORAGE_DISK)->url($user->driver_license_front);
		}
		if ($user->driver_license_back) {
			$status['driver_license_back_url'] = Storage::disk(self::STORAGE_DISK)->url($user->driver_license_back);
		}
		if ($user->my_number_card_front) {
			$status['my_number_card_front_url'] = Storage::disk(self::STORAGE_DISK)->url($user->my_number_card_front);
		}
		
		return $status;
	}
	
	/**
	 * Get pending verifications for admin
	 *
	 * @param int $perPage
	 * @return \Illuminate\Pagination\LengthAwarePaginator
	 */
	public function getPendingVerifications(int $perPage = 20)
	{
		return User::where('identity_status', User::IDENTITY_STATUS_PENDING)
			->orderBy('identity_submitted_at', 'asc')
			->paginate($perPage);
	}
	
	/**
	 * Validate document files based on document type
	 *
	 * @param string $documentType
	 * @param array $files
	 * @throws \InvalidArgumentException
	 */
	protected function validateDocumentFiles(string $documentType, array $files): void
	{
		if ($documentType === User::IDENTITY_DOC_DRIVER_LICENSE) {
			if (empty($files['driver_license_front'])) {
				throw new \InvalidArgumentException('Driver license front image is required');
			}
			if (empty($files['driver_license_back'])) {
				throw new \InvalidArgumentException('Driver license back image is required');
			}
		} elseif ($documentType === User::IDENTITY_DOC_MY_NUMBER_CARD) {
			if (empty($files['my_number_card_front'])) {
				throw new \InvalidArgumentException('My Number card front image is required');
			}
		}
	}
	
	/**
	 * Upload document files
	 *
	 * @param User $user
	 * @param string $documentType
	 * @param array $files
	 * @return array
	 */
	protected function uploadDocumentFiles(User $user, string $documentType, array $files): array
	{
		$uploadedPaths = [];
		$userFolder = self::STORAGE_PATH . '/' . $user->id;
		
		foreach ($files as $key => $file) {
			if ($file instanceof UploadedFile) {
				$filename = $key . '_' . time() . '_' . Str::random(10) . '.' . $file->getClientOriginalExtension();
				$path = $file->storeAs($userFolder, $filename, self::STORAGE_DISK);
				$uploadedPaths[$key] = $path;
			}
		}
		
		return $uploadedPaths;
	}
	
	/**
	 * Confirm all provisional orders for a user after identity approval
	 * Xử lý từng order riêng biệt: auto-charge credit card, gửi email riêng
	 *
	 * @param User $user
	 * @return array Kết quả xử lý các đơn hàng
	 */
	protected function confirmProvisionalOrders(User $user): array
	{
		$orders = Order::where('user_id', $user->id)
			->where('status', Order::STATUS_PROVISIONAL) // status = 9
			->where('auto_cancelled', false)
			->with(['order_detail', 'delivery'])
			->get();
		
		$results = [
			'total'   => $orders->count(),
			'success' => 0,
			'failed'  => 0,
			'orders'  => [],
		];
		
		foreach ($orders as $order) {
			$orderResult = $this->processProvisionalOrder($order, $user);
			$results['orders'][] = $orderResult;
			
			if ($orderResult['success']) {
				$results['success']++;
			} else {
				$results['failed']++;
			}
		}
		
		return $results;
	}
	
	/**
	 * Xử lý một đơn hàng provisional sau khi user được approve
	 * Chỉ xử lý payment và update status, KHÔNG gửi email (email được gửi tổng hợp trong approve())
	 *
	 * @param Order $order
	 * @param User $user
	 * @return array
	 */
	protected function processProvisionalOrder(Order $order, User $user): array
	{
		$result = [
			'order_id'        => $order->id,
			'order_code'      => $order->code,
			'success'         => false,
			'payment_success' => null,
			'message'         => '',
		];
		
		try {
			// Kiểm tra phương thức thanh toán
			// payment_method: 0 = Credit Card, 1 = Bank Transfer
			$isCardPayment = $order->payment_method == 0;
			$paymentToken = $order->payment_token;
			
			if ($isCardPayment && $paymentToken) {
				// Thực hiện auto-charge cho credit card
				$chargeResult = $this->chargeProvisionalOrder($order, $user);
				$result['payment_success'] = $chargeResult['success'];
				
				if ($chargeResult['success']) {
					// Thanh toán thành công
					$order->update([
						'status'                             => 0, // Status 0 = New/Confirmed
						'payment_status'                     => 1, // Đã thanh toán
						'payment_token'                      => null, // Xóa token sau khi charge
						'identity_verification_completed_at' => now(),
					]);
					$result['message'] = 'Thanh toán thành công';
				} else {
					// Thanh toán thất bại - giữ order nhưng đánh dấu lỗi
					$order->update([
						'status'                             => 0,
						'payment_status'                     => 0, // Chưa thanh toán
						'payment_error'                      => $chargeResult['error'],
						'identity_verification_completed_at' => now(),
					]);
					$result['message'] = 'Thanh toán thất bại: ' . $chargeResult['error'];
				}
			} else {
				// Bank Transfer hoặc không có card - chỉ update status
				$order->update([
					'status'                             => 0,
					'identity_verification_completed_at' => now(),
				]);
				$result['payment_success'] = null; // N/A cho bank transfer
				$result['message'] = 'Đơn hàng được xác nhận (chuyển khoản ngân hàng)';
			}
			
			$result['success'] = true;
			
			// NOTE: Không gửi email riêng lẻ ở đây nữa
			// Email tổng hợp chứa TẤT CẢ orders được gửi trong approve() method
			// theo yêu cầu Feedback #2
			
		} catch (\Exception $e) {
			$result['success'] = false;
			$result['message'] = 'Lỗi xử lý đơn hàng: ' . $e->getMessage();
			
			// Log lỗi
			\Log::error('Error processing provisional order', [
				'order_id' => $order->id,
				'user_id'  => $user->id,
				'error'    => $e->getMessage(),
			]);
		}
		
		return $result;
	}
	
	/**
	 * Thực hiện charge PayJP cho đơn hàng provisional
	 *
	 * @param Order $order
	 * @param User $user
	 * @return array
	 */
	protected function chargeProvisionalOrder(Order $order, User $user): array
	{
		try {
			// Set PayJP API key
			\Payjp\Payjp::setApiKey(config('services.payjp.secret_key'));
			
			// Kiểm tra customer ID
			if (!$user->payjp_customer_id) {
				return [
					'success' => false,
					'error'   => 'PayJP customer ID không tồn tại',
				];
			}
			
			// Retrieve PayJP customer
			$payjpCustomer = \Payjp\Customer::retrieve($user->payjp_customer_id);
			
			// Thực hiện charge
			$charge = \Payjp\Charge::create([
				'customer'    => $payjpCustomer->id,
				'card'        => $order->payment_token,
				'amount'      => (int)$order->total_price,
				'currency'    => 'jpy',
				'description' => 'Payment for Order #' . $order->code . ' (Identity Verified)',
			]);
			
			return [
				'success'   => true,
				'charge_id' => $charge->id,
			];
			
		} catch (\Payjp\Error\Card $e) {
			return [
				'success' => false,
				'error'   => 'カードエラー: ' . $e->getMessage(),
			];
		} catch (\Payjp\Error\InvalidRequest $e) {
			return [
				'success' => false,
				'error'   => 'リクエストエラー: ' . $e->getMessage(),
			];
		} catch (\Exception $e) {
			return [
				'success' => false,
				'error'   => $e->getMessage(),
			];
		}
	}
	
	/**
	 * Gửi email xác nhận đơn hàng sau khi identity approved
	 *
	 * @param Order $order
	 * @param User $user
	 * @param bool|null $paymentSuccess null = bank transfer, true/false = card result
	 * @return void
	 */
	protected function sendOrderConfirmationEmail(Order $order, User $user, ?bool $paymentSuccess): void
	{
		try {
			Mail::to($user->email)->send(new ProvisionalOrderConfirmed($order, $user, $paymentSuccess));
		} catch (\Exception $e) {
			\Log::error('Failed to send order confirmation email', [
				'order_id' => $order->id,
				'user_id'  => $user->id,
				'error'    => $e->getMessage(),
			]);
		}
	}
	
	/**
	 * Update provisional orders after rejection
	 *
	 * @param User $user
	 * @param int $rejectionCount
	 * @return void
	 */
	protected function updateProvisionalOrdersAfterRejection(User $user, int $rejectionCount): void
	{
		\Log::info('Processing identity rejection for user', [
			'user_id' => $user->id,
			'rejection_count' => $rejectionCount,
			'max_rejection_count' => self::MAX_REJECTION_COUNT,
		]);

		// Tìm đơn hàng provisional bằng status = 9
		$orders = Order::where('user_id', $user->id)
			->where('status', Order::STATUS_PROVISIONAL)
			->where(function ($query) {
				$query->where('auto_cancelled', false)
					->orWhereNull('auto_cancelled');
			})
			->get();

		\Log::info('Found provisional orders for rejection processing', [
			'user_id' => $user->id,
			'order_count' => $orders->count(),
			'order_ids' => $orders->pluck('id')->toArray(),
		]);

		foreach ($orders as $order) {
			if ($rejectionCount >= self::MAX_REJECTION_COUNT) {
				// Cancel order if max rejections reached
				\Log::info('Auto cancelling order due to max rejections', [
					'order_id' => $order->id,
					'order_code' => $order->code,
					'rejection_count' => $rejectionCount,
				]);
				$this->cancelProvisionalOrder($order, '本人確認が2回却下されたため、自動キャンセルされました');
			} else {
				// Give 2 more days for resubmission
				\Log::info('Extending provisional order expiration', [
					'order_id' => $order->id,
					'order_code' => $order->code,
					'new_expiration' => now()->addDays(self::RESUBMISSION_EXPIRATION_DAYS)->toDateTimeString(),
				]);
				$order->update([
					'provisional_expires_at' => now()->addDays(self::RESUBMISSION_EXPIRATION_DAYS),
				]);
			}
		}
	}
}
