<?php

namespace App\Http\Controllers;

use App\Product;
use App\User;
use App\UserCard;
use App\UserPaymentHistory;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\DeliveryAddress;
use App\Order;
use App\OrderDetail;
use App\Payment;
use App\ProductDetail;
use App\ShippingRate;
use App\Events\NotifyEvent;
use App\Notify;
use Validator;
//Payment by PayJP
use Payjp\Charge;
use Payjp\Payjp;
use Payjp\Util;
use App\ProductSchedule;
use App\Traits\SendsTemplateEmail;
use Cart;
use function PHPUnit\Framework\logicalOr;


class CartController extends Controller
{
	use SendsTemplateEmail;

	const ITEM_PER_PAGE = 25;
	
	public function index()
	{
		$cartContentItems = Cart::getContent();
		$cartTotalAmount = Cart::getTotal();
		$totalShipping = 0;

		$cartCollection = $cartContentItems->sortBy(function ($product, $key) {
			return $product->attributes->created_at;
		});

		$productIds = $cartCollection->pluck('attributes.id')->filter()->unique()->values()->all();
		$products = [];
		if (!empty($productIds)) {
			$products = Product::with('color_detail.color')
				->whereIn('id', $productIds)
				->get()
				->keyBy('id');
		}

		$list = [];
		foreach ($cartCollection as $item) {
			$pid = $item->attributes->id ?? null;
			$product = $pid && isset($products[$pid]) ? $products[$pid] : null;
			$arr = $item->toArray();
			$arr['attributes']['size'] = $product ? $product->size : null;
			$arr['attributes']['color_detail'] = $product ? $product->color_detail : [];
			$list[] = $arr;
		}

		return response()->json([
			'status'         => 'success',
			'data'           => $list,
			'total'          => $cartCollection->count(),
			'total_amount'   => $cartTotalAmount + $totalShipping,
			'total_shipping' => $totalShipping,
		], 200);
	}
	
	public function statistic()
	{
		//$cartTotal = Cart::getTotalQuantity();
		//Cart::clear();
		
		$cartCollection = Cart::getContent();
		$cartTotal = $cartCollection->count();
		
		return response()->json(['status' => 'success', 'data' => ['total' => $cartTotal]], 200);
	}
	
	public function show($id = 0)
	{
		$item = Cart::get($id);
		
		return response()->json(['status' => 'success', 'data' => $item], 200);
	}
	
	public function store(Request $request)
	{
		$validator = Validator::make($request->all(), [
			'id'   => ['required'],
			'date' => ['required'],
			/*'height'    => [ 'required' ],
			'hip'       => [ 'required' ],
			'tabi'      => [ 'required' ],
			'towel'     => [ 'required' ],
			'safe_pack' => [ 'required' ],
			'package'   => [ 'required' ],*/
		]);
		
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$params = $request->all();
		
		$product = Product::with('category', 'color_detail', 'schedule', 'user')
			->isPublished()
			->where('id', $params['id'])
			->first();
		
		if (!$product) return response()->json(['status' => 'error', 'errors' => __('messages.product_not_found')], 200);

		$selectedDate = Carbon::parse($params['date']);
		$minReservationDate = Carbon::today()->addDays((int) config('rental_dates.min_days_before_reservation', 18));
		if ($selectedDate->lt($minReservationDate)) {
			return response()->json(['status' => 'error', 'errors' => '着用予定日の18日前まで予約可能です。別の日付をお選びください。'], 200);
		}

		// 選択した着用日の確保期間 [W-10, W+50] が既存ブロックと重なるかチェック
		// 新規注文は発送準備から返却後の検品期間まで確保する必要があるため、その範囲に既存ブロックが1件でもあれば不可
		$blockBefore = config('rental_dates.block_days_before', 10);
		$blockAfter = config('rental_dates.block_days_after', 50);
		$conflicting = ProductSchedule::where('product_id', $product->id)
			->whereBetween('short_date', [
				$selectedDate->copy()->subDays($blockBefore)->toDateString(),
				$selectedDate->copy()->addDays($blockAfter)->toDateString(),
			])
			->exists();
		if ($conflicting) {
			return response()->json(['status' => 'error', 'errors' => '選択した日付は予約できません。別の日付をお選びください。'], 200);
		}

		// カートには1点のみ追加可能（1点ずつのご注文をお願いする運用）
		$cartCollection = Cart::getContent();
		if ($cartCollection->count() > 0) {
			foreach ($cartCollection as $existingItem) {
				if (isset($existingItem->attributes['id']) && $existingItem->attributes['id'] == $product->id) {
					return response()->json(['status' => 'error', 'errors' => 'この商品は既にカートに入っています。'], 200);
				}
			}
			return response()->json([
				'status' => 'error',
				'errors' => '1点ずつのご注文をお願いしております。先にカート内の商品をご注文いただくか、カートから削除してから新しい商品を追加してください。'
			], 200);
		}

		$cartId = md5($product->id . "_" . $params['package'] . "_" . str_replace("-", "_", str_replace("/", "_", $params['date'])));
		$cItem = Cart::get($cartId);
		
		if (!isset($cItem) || $cItem == null) {
			$package = 0; //$params['package'];
			$productName = $product->name;
			$productOriginPrice = ($params['package'] == 0) ? $product->default_price : $product->regular_price_from;
			$safe_pack = 0; //($package == 0 && $params['safe_pack'] == 1) ? 1100 : 0;
			$tabi = 0; //($package == 0 && $params['tabi'] == 1) ? 660 : 0;
			$towel = 0; //($package == 0 && $params['towel'] == 1) ? 264 : 0;
			$productTax = $productOriginPrice * (10 / 100);
			$productPrice = $productOriginPrice + $productTax;
			$productPrice += $safe_pack + $tabi + $towel;
			
			$shippingDate = $params['date'];
			if ($package == 0) {
				// 当店発送予定日 = 着用日 - store_shipping_days（仕様: 着用日10日前に当店発送）
				$storeShippingDays = (int) config('rental_dates.store_shipping_days', 10);
				$shippingDate = Carbon::parse($params['date'])->subDays($storeShippingDays);
				$shippingDate = $shippingDate->format('Y-m-d');
			}
			
			$cartData = [
				'id'         => $cartId,
				'name'       => $productName,
				'price'      => $productPrice,
				'quantity'   => 1,
				'attributes' => [
					'id'              => $product->id,
					'name'            => $product->name,
					'type'            => $product->type,
					'package'         => $package,
					'image'           => $product->image,
					'origin_price'    => $productOriginPrice,
					'tax'             => $productTax,
					'price'           => $productOriginPrice + $productTax,
					'shipping_date'   => $shippingDate,
					'wear_date'       => $params['date'],
					'height'          => null, //$params['height'],
					'hip'             => null, //$params['hip'],
					'foot'            => null, //isset($params['foot']) ? $params['foot'] : null,
					'charged_options' => [
						'safe_pack' => ['value' => $params['safe_pack'], 'price' => $safe_pack, 'origin_price' => 1000],
						'tabi'      => ['value' => $params['tabi'], 'price' => $tabi, 'origin_price' => 600],
						'towel'     => ['value' => $params['towel'], 'price' => $towel, 'origin_price' => 240],
					],
					'free_options'    => [
						['name' => '帯枕', 'value' => '変更しない'],
						['name' => 'マジックベルト', 'value' => '変更しない'],
						['name' => '三連紐', 'value' => '追加しない'],
					],
					'created_at'      => date('YmdHis'),
				]
			];
			Cart::add($cartData);
			
			return response()->json(['status' => 'success', 'message' => ''], 200);
		} else {
			/*Cart::update($product->id, [ 'quantity' => 1 ]);*/
			
			return response()->json(['status' => 'error', 'message' => __('messages.product_already_ordered')], 200);
		}
	}
	
	public function update(Request $request, $id)
	{
		//{ type: type, value: val }
		$validator = Validator::make($request->all(), [
			'type'  => ['required'],
			'value' => ['required']
		]);
		if ($validator->fails()) return response()->json(['status' => 'error', 'message' => __('messages.product_not_found')], 200);
		
		$cItem = Cart::get($id);
		
		if ($cItem) {
			$params = $request->all();
			$product = Product::with('category', 'color_detail', 'schedule', 'user')
				->isPublished()
				->where('id', $cItem->attributes->id)
				->first();
			
			if (!$product) return response()->json(['status' => 'error', 'message' => __('messages.product_not_found')], 200);
			
			$package = $cItem->attributes->package;
			$shipping_date = $cItem->attributes->shipping_date;
			$wear_date = $cItem->attributes->wear_date;
			$height = $cItem->attributes->height;
			$hip = $cItem->attributes->hip;
			$foot = $cItem->attributes->foot;
			$created_at = $cItem->attributes->created_at;
			$safe_pack = $cItem->attributes->charged_options['safe_pack']['value'];
			$tabi = $cItem->attributes->charged_options['tabi']['value'];
			$towel = $cItem->attributes->charged_options['towel']['value'];
			
			if ($params['type'] == 'safe_pack') {
				$safe_pack = ($params['value'] == 1 || $params['value'] == '1') ? 1 : 0;
			} elseif ($params['type'] == 'tabi') {
				$tabi = ($params['value'] == 1 || $params['value'] == '1') ? 1 : 0;
			} elseif ($params['type'] == 'towel') {
				$towel = ($params['value'] == 1 || $params['value'] == '1') ? 1 : 0;
			}
			$safe_pack_price = ($safe_pack == 1) ? 1100 : 0;
			$tabi_price = ($tabi == 1) ? 660 : 0;
			$towel_price = ($towel == 1) ? 264 : 0;
			
			$productOriginPrice = ($package == 0) ? $product->default_price : $product->regular_price_from;
			$productTax = $productOriginPrice * (10 / 100);
			$productPrice = $productOriginPrice + $productTax;
			$productPrice += $safe_pack_price + $tabi_price + $towel_price;
			
			$cartData = [
				'price'      => $productPrice,
				'attributes' => [
					'id'              => $product->id,
					'name'            => $product->name,
					'type'            => $product->type,
					'package'         => $package,
					'image'           => $product->image,
					'origin_price'    => $productOriginPrice,
					'tax'             => $productTax,
					'price'           => $productOriginPrice + $productTax,
					'shipping_date'   => $shipping_date,
					'wear_date'       => $wear_date,
					'height'          => $height,
					'hip'             => $hip,
					'foot'            => $foot,
					'charged_options' => [
						'safe_pack' => ['value' => $safe_pack, 'price' => $safe_pack_price, 'origin_price' => 1000],
						'tabi'      => ['value' => $tabi, 'price' => $tabi_price, 'origin_price' => 600],
						'towel'     => ['value' => $towel, 'price' => $towel_price, 'origin_price' => 240],
					],
					'free_options'    => [
						['name' => '帯枕', 'value' => '変更しない'],
						['name' => 'マジックベルト', 'value' => '変更しない'],
						['name' => '三連紐', 'value' => '追加しない'],
					],
					'created_at'      => $created_at
				],
				//'quantity' => [ 'relative' => false, 'value'    => $quantity ],
			];
			
			Cart::update($id, $cartData);
			
			return response()->json(['status' => 'success', 'message' => '', 'data' => $cartData], 200);
		} else {
			return response()->json(['status' => 'error', 'message' => __('messages.product_not_found')], 200);
		}
	}
	
	public function updateQuantity(Request $request, $id) {
		$validator = Validator::make($request->all(), [
			'quantity'  => ['required'],
		]);
		if ($validator->fails()) return response()->json(['status' => 'error', 'message' => __('messages.product_not_found')], 200);
		$params = $request->all();
		
		$cItem = Cart::get($id);
		if (isset($cItem) && $cItem != null) {
			Cart::update($id, [
				'quantity' => [
					'relative' => false,
					'value'    => ($params['quantity'] > 0) ? $params['quantity'] : 1
				],
			]);
		}
		
		return response()->json(['status' => 'success', 'message' => ''], 200);
	}
	
	public function order(Request $request)
	{
		$validator = Validator::make($request->all(), [
			'payment_method' => ['required'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		$params = $request->all();
		$cartTotalAmount = Cart::getTotal();
		if ($cartTotalAmount <= 0) return response()->json(['status' => 'error', 'code' => null], 200);

		if ((string) $params['payment_method'] === '0') {
			return response()->json([
				'status'  => 'error',
				'message' => 'クレジットカード注文は現在のチェックアウト画面からカード登録済みの状態でお申し込みください。',
			], 422);
		}
		
		$orderCode = $this->generateUniqueOrderCode();
		
		$userId = auth('api')->user()->id;
		$user = User::where('id', $userId)->first();
		
		$paymentResult = null;
		$paymentCustomer = null;
		
		$paymentStatus = ($params['payment_method'] == 0 && ($paymentResult != null)) ? 1 : 0;

		// Check user identity verification status
		// Status 9: Identity Verification Pending (本人確認待ち)
		$isProvisional = ($user->identity_status !== 'approved');
		$orderStatus = $isProvisional ? Order::STATUS_PROVISIONAL : Order::STATUS_NEW;

		//Order
		$orderData = [
			'code'           => $orderCode,
			'type'           => "user",
			'user_id'        => $userId,
			'total_price'    => $cartTotalAmount,
			'shipping_cost'  => 0,
			'note'           => $params['note'],
			'payment_method' => in_array($params['payment_method'], [0, 1, 2, 3]) ? $params['payment_method'] : 3,
			'payment_status' => $paymentStatus,
			'status'         => $orderStatus, //0: New order and wait confirm, 9: Identity Verification Pending
			'created_at'     => date('Y-m-d H:i:s'),
			'updated_at'     => date('Y-m-d H:i:s'),
		];

		// Set provisional order fields if identity not approved
		if ($isProvisional) {
			$orderData['provisional_created_at'] = now();
			$orderData['provisional_expires_at'] = now()->addDays(3);
			$orderData['identity_verification_required'] = true;
		}

		$order = Order::create($orderData);
		
		//Order Detail
		$cartCollection = Cart::getContent();
		foreach ($cartCollection as $item) {
			$product = Product::where('id', $item['attributes']['id'])->first();
			
			$freeOptions = "";
			foreach ($item['attributes']['free_options'] as $optItem) {
				$freeOptions .= ($freeOptions != "") ? "|" . $optItem['name'] : $optItem['name'];
			}

			$detail = OrderDetail::create([
				'order_id'      => $order->id,
				'product_id'    => $item['attributes']['id'],
				'product_name'  => $item['name'],
				'product_image' => $item['attributes']['image'],
				'product_type'  => $item['attributes']['type'], //add
				'order_method'  => $item['attributes']['package'],
				'catalog_price' => $item['attributes']['origin_price'],
				'discount'      => $product->discount,
				'price'         => $item['attributes']['price'],
				'tax'           => $item['attributes']['tax'], //add
				'shipping_cost' => 0,
				'shipping_date' => $item['attributes']['shipping_date'], //add
				'wear_date'     => $item['attributes']['wear_date'], //add
				'height'        => $item['attributes']['height'], //add
				'hip'           => $item['attributes']['hip'], //add
				'foot'          => $item['attributes']['foot'], //add
				'safe_pack'     => $item['attributes']['charged_options']['safe_pack']['price'], //add
				'tabi'          => $item['attributes']['charged_options']['tabi']['price'], //add
				'towel'         => $item['attributes']['charged_options']['towel']['price'], //add
				'free_options'  => $freeOptions, //add
				'quantity'      => $item['quantity'],
				'total_price'   => $item['price'],
				'created_at'    => date('Y-m-d H:i:s'),
				'updated_at'    => date('Y-m-d H:i:s'),
			]);

			// ブロックデート自動登録（着用日±7日）
			if ($product && $detail->wear_date) {
				$this->registerOrderBlockDates($product->id, $detail->wear_date, $order->id);
			}
		}

		//DeliveryAddress
		DeliveryAddress::create([
			'order_id'            => $order->id,
			'first_name'          => $user->full_name,
			'last_name'           => $user->full_name,
			'furigana_first_name' => $user->furigana_name,
			'furigana_last_name'  => $user->furigana_name,
			'post_code'           => $user->post_code,
			'city'                => $user->city,
			'district'            => $user->district,
			'address'             => $user->address . $user->address2,
			'phone_number'        => $user->phone_number,
			'mobile_tel'          => $user->mobile_tel,
			'email'               => $user->email,
			'user_id'             => $userId,
			'is_default'          => 0,
			'created_at'          => date('Y-m-d H:i:s'),
			'updated_at'          => date('Y-m-d H:i:s'),
		]);
		
		//Payment
		$payment = null;
		if ($params['payment_method'] == 0 && $paymentResult != null) {
			$paymentResultJs = json_encode($paymentResult);
			$paymentResultArr = json_decode($paymentResultJs, true);
			
			$payment = Payment::create([
				'order_id'               => $order->id,
				'code'                   => $paymentResultArr['id'],
				'total'                  => $paymentResultArr['amount'],
				'amount_captured'        => $paymentResultArr['amount_captured'],
				'amount_refunded'        => $paymentResultArr['amount_refunded'],
				'application_fee'        => $paymentResultArr['application_fee'],
				'application_fee_amount' => $paymentResultArr['application_fee_amount'],
				'currency'               => $paymentResultArr['currency'],
				'type'                   => $paymentResultArr['payment_method_details']['type'],
				'provider'               => $paymentResultArr['balance_transaction'],
				'customer'               => $paymentResultArr['customer'],
				'payment_method'         => $paymentResultArr['payment_method'],
				'brand'                  => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['brand'] : '',
				'funding'                => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['funding'] : '',
				'network'                => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['network'] : '',
				'country'                => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['country'] : '',
				'last4'                  => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['last4'] : '',
				'exp_month'              => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['exp_month'] : '',
				'exp_year'               => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['exp_year'] : '',
				'failure_code'           => $paymentResultArr['failure_code'],
				'failure_message'        => $paymentResultArr['failure_message'],
				'content'                => json_encode($paymentResult),
				'customer_info'          => json_encode($paymentCustomer),
				/*'error_content'          => $paymentResultArr['amount_refunded'],*/
				'finished_at'            => date('Y-m-d H:i:s', $paymentResultArr['created']),
				'status'                 => ($paymentResultArr['paid'] && $paymentResultArr['status'] == "succeeded") ? 1 : 0,
				'created_at'             => date('Y-m-d H:i:s'),
				'updated_at'             => date('Y-m-d H:i:s'),
			]);
		}
		
		// Prepare email data from cart BEFORE clearing
		// Get product info from order details (already created from cart)
		$orderDetails = OrderDetail::where('order_id', $order->id)->get();
		$productCodes = [];
		$productPrices = [];
		$optionPrices = [];
		$shippingCosts = [];
		$wearDates = [];
		$rentalPeriods = [];

		foreach ($orderDetails as $detail) {
			$productCodes[] = $detail->product_name;
			$productPrices[] = $detail->price;
			$optionPrices[] = ($detail->safe_pack ?? 0) + ($detail->tabi ?? 0) + ($detail->towel ?? 0);
			$shippingCosts[] = $detail->shipping_cost ?? 0;

			// Format wear date
			if ($detail->wear_date) {
				$wearDateFormatted = date('Y/m/d', strtotime($detail->wear_date));
				$wearDates[] = $wearDateFormatted;

				$rentalDates = $this->buildRentalMailDates($detail->wear_date);
				$rentalPeriods[] = $rentalDates['rental_start_date'] . ' ～ ' . $rentalDates['rental_end_date'];
			}
		}

		//Clear Cart
		Cart::clear();

		//Send Email
		$data = $params;
		$data['site'] = url("/");
		$data['code'] = $orderCode;
		$totalShippingOrder = array_sum($shippingCosts);
		$data['total_amount'] = "¥" . number_format($cartTotalAmount + $totalShippingOrder);

		// Payment method mapping
		$paymentMethodMap = [
			0 => 'クレジットカード',
			1 => '後払い',
			2 => '銀行振込',
			3 => '代金引換'
		];
		$data['payment_method'] = $paymentMethodMap[$params['payment_method']] ?? '前払い';
		$data['payment_status'] = ($params['payment_method'] == 0 && $payment != null && $payment->status == 1) ? "有料" : "未払い";
		$data['note'] = $params['note'];
		$data['name'] = $user->full_name;
		$data['furigana'] = $user->furigana_name;
		$data['address'] = "〒" . $user->post_code . " " . $user->city . " " . $user->district . " " . $user->address . " " . $user->address2;
		$data['phone_number'] = $user->phone_number;
		$data['email'] = $user->email;

		// Additional data for provisional order email template
		$data['product_code'] = implode(', ', $productCodes);
		$data['product_price'] = "¥" . number_format(array_sum($productPrices));
		$data['option_price'] = "¥" . number_format(array_sum($optionPrices));
		$data['shipping_cost'] = "¥" . number_format(array_sum($shippingCosts));
		$data['wear_date'] = !empty($wearDates) ? implode(', ', $wearDates) : '未定';
		$data['wearing_date'] = $data['wear_date'];
		$data['rental_period'] = !empty($rentalPeriods) ? implode(', ', $rentalPeriods) : '未定';

		// Calculate dates for rental flow
		if (!empty($wearDates)) {
			$data = array_merge($data, $this->buildRentalMailDates($orderDetails->first()->wear_date));
		} else {
			$data['rental_start_date'] = '';
			$data['rental_end_date'] = '';
			$data['arrival_date'] = '未定';
			$data['shipping_date'] = '未定';
			$data['return_date'] = '未定';
			$data['store_arrival_date'] = '未定';
		}

		$userEmail = $user->email;
		$notifyContent = ['code' => $orderCode];
		$productNames = $cartCollection->pluck('name')->implode('、');

		try {
			Notify::create([
				'content'      => "新規注文がありました #" . $orderCode . "（" . ($user->full_name ?? '') . " / " . $productNames . "）",
				'module'       => 'order',
				'item_id'      => $orderCode,
				'item_content' => json_encode($notifyContent),
				'created_at'   => date('Y-m-d H:i:s'),
				'updated_at'   => date('Y-m-d H:i:s'),
			]);
			event(new NotifyEvent());
			
			// CMS テンプレート用の変数
			$templateVars = [
				'full_name'      => $user->full_name,
				'first_name'     => $user->first_name ?? '',
				'last_name'      => $user->last_name ?? '',
				'email'          => $user->email,
				'order_code'     => $orderCode,
				'total_price'    => $data['total_amount'] ?? number_format($cartTotalAmount),
				'payment_method' => $data['payment_method'] ?? '',
				'payment_status' => $data['payment_status'] ?? '未払い',
				'wearing_date'   => $data['wear_date'] ?? '未定',
				'order_detail'   => $this->buildOrderDetailHtml($data),
				'rental_flow'    => $this->buildRentalFlowHtml($data),
			];

			// 管理者向けメール（CMS テンプレート）
			$this->sendTemplateEmail(
				'm_order_received',
				config('settings.admin_email'),
				$templateVars
			);
			logger("[Email] Sent admin order email to: " . config('settings.admin_email'));

			// ユーザー向けメール（CMS テンプレート）
			$pmCode = $params['payment_method'] ?? 1;
			if ($isProvisional) {
				$userSlug = ($pmCode == 0) ? 'u_provisional_order_credit' : 'u_provisional_order_bank';
			} else {
				$userSlug = ($pmCode == 0) ? 'u_order_confirmed_credit' : 'u_order_confirmed_bank';
			}
			$this->sendTemplateEmail($userSlug, $userEmail, $templateVars);
			logger("[Email] Sent user order email ({$userSlug}) to: " . $userEmail);
		} catch (\Exception $exception) {
			logger($exception->getMessage());
		} finally {
			return response()->json(['status' => 'success', 'code' => $orderCode], 200);
		}
	}
	
	public function destroy($id)
	{
		$cItem = Cart::get($id);
		if ($cItem) {
			Cart::remove($id);
			return response()->json(['status' => 'success', 'message' => ''], 200);
		}
		
		return response()->json(['status' => 'error', 'message' => __('messages.product_not_found')], 200);
	}
	
	public function clear()
	{
		Cart::clear();
		
		return response()->json(['status' => 'success', 'message' => ''], 200);
	}
	
	public function payment(Request $request)
	{
		$cartTotalAmount = Cart::getTotal();
		if ($cartTotalAmount <= 0) return response()->json(['errors' => __('messages.product_not_compatible')], 403);

		$params = $request->all();
		$cartData = $params['cart'] ?? [];

		// Lấy shipping address từ request
		$shippingAddress = $cartData['shipping_address'] ?? null;
		if (!$shippingAddress) {
			return response()->json(['errors' => '配送先住所を選択してください。'], 403);
		}

		// 送料はクライアント値を信用せず、配送先住所と商品金額からサーバ側で再計算する。
		// （以前は cartData['shipping_cost'] をそのまま請求額に使っていたため、
		//   shipping_cost:0 や負値の送信で過少請求が可能だった）
		$shipPrefecture = $shippingAddress['province'] ?? $shippingAddress['district'] ?? '';
		$shipPostal     = $shippingAddress['postal_code'] ?? $shippingAddress['post_code'] ?? '';
		[$totalShipping] = $this->computeShippingCost($shipPrefecture, $shipPostal, $cartTotalAmount);

		$sum = $cartTotalAmount + $totalShipping;
		$totalAmount = (int) $sum;

		// Xác định phương thức thanh toán
		$paymentMethod = $cartData['payment_method'] ?? 1;
		$paymentCardId = $cartData['payment_card_id'] ?? null;
		$token = $params['token'] ?? null;

		$orderCode = $this->generateUniqueOrderCode();

		$userId = auth('api')->user()->id;
		$user = User::where('id', $userId)->first();

		// カート内の商品がレンタル中でないか再チェック（二重注文防止）
		// lockForUpdate で注文作成完了まで他リクエストの割り込みを防止
		$cartCollection = Cart::getContent();
		$lockedProducts = [];
		\DB::beginTransaction();
		try {
			foreach ($cartCollection as $item) {
				$product = Product::where('id', $item['attributes']['id'])->lockForUpdate()->first();
				// 着用日の確保期間 [W-7, W+50] と既存ブロックが重ならないかチェック
				$wearDate = Carbon::parse($item['attributes']['wear_date']);
				$blockBefore = config('rental_dates.block_days_before', 7);
				$blockAfter = config('rental_dates.block_days_after', 50);
				$dateConflict = ProductSchedule::where('product_id', $item['attributes']['id'])
					->whereBetween('short_date', [
						$wearDate->copy()->subDays($blockBefore)->toDateString(),
						$wearDate->copy()->addDays($blockAfter)->toDateString(),
					])
					->exists();
				if ($dateConflict) {
					\DB::rollBack();
					return response()->json([
						'errors' => '商品「' . $item['name'] . '」の選択した日付は他のご予約と重複しています。カートを確認してください。'
					], 403);
				}
				$lockedProducts[$item['attributes']['id']] = $product;
			}

		// Kiểm tra user đã xác thực hay chưa
		$isUserVerified = $user->identity_status === 'approved';
		$isProvisionalOrder = !$isUserVerified;

		$chargeCardId = null;
		$payjpCustomer = null;
		$userCard = null;

		// Nếu thanh toán bằng thẻ tín dụng (payment_method = 0)
		if ($paymentMethod == 0) {
			Payjp::setApiKey(config('payjp.secret_key'));

			// Kiểm tra customer PayJP
			if (!$user->payjp_customer_id) {
				\DB::rollBack();
				return response()->json(['errors' => 'お客様情報が見つかりません。カードを登録してください。'], 403);
			}

			try {
				$payjpCustomer = \Payjp\Customer::retrieve($user->payjp_customer_id);
			} catch (\Exception $e) {
				\DB::rollBack();
				return response()->json(['errors' => 'お客様情報が見つかりません。'], 403);
			}

			// Xác định card ID để charge
			if ($paymentCardId) {
				// Lấy payjp_card_id từ UserCard
				$userCard = UserCard::where('id', $paymentCardId)
					->where('user_id', $userId)
					->where('is_activated', 1)
					->where('is_deleted', 0)
					->whereIn('payjp_three_d_secure_status', ['verified', 'attempted'])
					->first();

				if (!$userCard) {
					\DB::rollBack();
					return response()->json(['errors' => 'カードが見つかりません。'], 403);
				}

				$chargeCardId = $userCard->payjp_card_id;
			}

			// Nếu không có card cụ thể, dùng default card đã hoàn了 3Dセキュア
			if (!$chargeCardId) {
				$defaultCard = UserCard::where('user_id', $userId)
					->where('is_default', 1)
					->where('is_activated', 1)
					->where('is_deleted', 0)
					->whereIn('payjp_three_d_secure_status', ['verified', 'attempted'])
					->first();
				if ($defaultCard) {
					$chargeCardId = $defaultCard->payjp_card_id;
					$userCard = $defaultCard;
				}
			}

			if (!$chargeCardId) {
				\DB::rollBack();
				return response()->json(['errors' => 'カードが登録されていません。'], 403);
			}

			if ($userCard && $userCard->card_exp_month && $userCard->card_exp_year) {
				$earliestPaymentDate = null;
				foreach ($cartCollection as $item) {
					$wearDate = Carbon::parse($item['attributes']['wear_date']);
					$paymentDate = $wearDate->copy()->subDays((int) config('rental_dates.payment_deadline_days', 11));
					if ($earliestPaymentDate === null || $paymentDate->lt($earliestPaymentDate)) {
						$earliestPaymentDate = $paymentDate;
					}
				}

				$expiryYear = (int) $userCard->card_exp_year;
				if ($expiryYear < 100) {
					$expiryYear += 2000;
				}
				$expiryEndDate = Carbon::create($expiryYear, (int) $userCard->card_exp_month, 1)->endOfMonth();
				if ($earliestPaymentDate && $expiryEndDate->lt($earliestPaymentDate)) {
					\DB::rollBack();
					return response()->json([
						'errors' => '選択中のカードは決済予定日前に有効期限が切れるため、この注文には使用できません。別のカードを選択するか、カード情報を更新してください。',
					], 403);
				}
			}

			// カード情報を保存のみ（決済は着用日11日前に自動実行）
		}

		// ステータス決定
		// Status: 0 = New, 9 = Identity Verification Pending (仮予約)
		$orderStatus = $isProvisionalOrder ? 9 : 0;
		// 決済は着用日11日前に自動実行するため、注文時点では常に未決済
		$paymentStatus = 0;

		// フロントから送信された着用者情報・備考のマップを構築
		$itemDetailsMap = [];
		if (isset($cartData['item_details']) && is_array($cartData['item_details'])) {
			foreach ($cartData['item_details'] as $detailInput) {
				$cartId = $detailInput['cart_id'] ?? null;
				if ($cartId) {
					$itemDetailsMap[$cartId] = $detailInput;
				}
			}
		}

		//Order
		$orderData = [
			'code'           => $orderCode,
			'type'           => "user",
			'user_id'        => $userId,
			'total_price'    => $totalAmount,
			'shipping_cost'  => $totalShipping,
			'note'           => '',
			'payment_method' => $paymentMethod,
			'payment_status' => $paymentStatus,
			'status'         => $orderStatus,
			'created_at'     => date('Y-m-d H:i:s'),
			'updated_at'     => date('Y-m-d H:i:s'),
		];

		// クレカ払いの場合、カードIDを保存（着用日11日前に自動決済で使用）
		if ($paymentMethod == 0 && $chargeCardId) {
			$orderData['payment_card_id'] = $chargeCardId;
		}

		// 仮予約（未認証ユーザー）の場合
		if ($isProvisionalOrder) {
			$orderData['provisional_created_at'] = now();
			$orderData['provisional_expires_at'] = now()->addDays(3);
			$orderData['identity_verification_required'] = true;
		}

		$order = Order::create($orderData);
		
		//Order Detail
		foreach ($cartCollection as $item) {
			$product = $lockedProducts[$item['attributes']['id']] ?? null;
			$cartItemId = $item['id'] ?? null;
			$userInput = $cartItemId && isset($itemDetailsMap[$cartItemId]) ? $itemDetailsMap[$cartItemId] : [];
			$preferredDeliveryTime = $userInput['preferred_delivery_time'] ?? null;
			$heightValue = $userInput['height'] ?? $item['attributes']['height'];
			$hipValue = $userInput['hip'] ?? $item['attributes']['hip'];
			$footValue = $userInput['foot'] ?? $item['attributes']['foot'];
			$detailNote = $userInput['note'] ?? '';

			$detail = OrderDetail::create([
				'order_id'                => $order->id,
				'product_id'              => $item['attributes']['id'],
				'product_name'            => $item['name'],
				'product_image'           => $item['attributes']['image'],
				'product_type'            => $item['attributes']['type'], //add
				'order_method'            => $item['attributes']['package'],
				'catalog_price'           => $item['attributes']['origin_price'],
				'discount'                => $product ? $product->discount : 0,
				'price'                   => $item['attributes']['price'],
				'tax'                     => $item['attributes']['tax'], //add
				'shipping_cost'           => 0,
				'shipping_date'           => $item['attributes']['shipping_date'], //add
				'wear_date'               => $item['attributes']['wear_date'], //add
				'preferred_delivery_time' => $preferredDeliveryTime,
				'note'                    => $detailNote,
				'height'                  => $heightValue,
				'hip'                     => $hipValue,
				'foot'                    => $footValue,
				'safe_pack'               => $item['attributes']['charged_options']['safe_pack']['price'], //add
				'tabi'                    => $item['attributes']['charged_options']['tabi']['price'], //add
				'towel'                   => $item['attributes']['charged_options']['towel']['price'], //add
				'free_options'            => "", //add
				'quantity'                => $item['quantity'],
				'total_price'             => $item['price'],
				'created_at'              => date('Y-m-d H:i:s'),
				'updated_at'              => date('Y-m-d H:i:s'),
			]);

			// ブロックデート自動登録（着用日±7日）
			if ($product && $detail->wear_date) {
				$this->registerOrderBlockDates($product->id, $detail->wear_date, $order->id);
			}
		}

		//DeliveryAddress - Sử dụng địa chỉ từ checkout form
		$deliveryData = [
			'first_name'          => $shippingAddress['first_name'] ?? $user->full_name,
			'last_name'           => $shippingAddress['last_name'] ?? '',
			'furigana_first_name' => $shippingAddress['furigana_first_name'] ?? $user->furigana_name,
			'furigana_last_name'  => $shippingAddress['furigana_last_name'] ?? '',
			'post_code'           => $shippingAddress['postal_code'] ?? $shippingAddress['post_code'] ?? $user->post_code,
			'city'                => $shippingAddress['city'] ?? $user->city,
			'district'            => $shippingAddress['province'] ?? $shippingAddress['district'] ?? $user->district,
			'address'             => trim(($shippingAddress['street_address'] ?? '') . ' ' . ($shippingAddress['building_name'] ?? '')),
			'phone_number'        => $shippingAddress['phone_number'] ?? $user->phone_number,
			'mobile_tel'          => $shippingAddress['mobile_tel'] ?? $user->mobile_tel,
			'email'               => $shippingAddress['email'] ?? $user->email,
			'user_id'             => $userId,
			'is_default'          => 0,
			'created_at'          => date('Y-m-d H:i:s'),
			'updated_at'          => date('Y-m-d H:i:s'),
		];

		// 注文の配送先スナップショット（住所帳には出さない＝連続注文で同じ住所が重複表示されない）
		DeliveryAddress::create(array_merge($deliveryData, [
			'order_id'  => $order->id,
			'is_hidden' => 1,
		]));

		// 住所帳: 同一内容の住所が無い場合のみ可視行を追加（次回チェックアウトで選択可能にする）
		$existsInAddressBook = DeliveryAddress::where('user_id', $userId)
			->where('is_hidden', 0)
			->where('first_name', $deliveryData['first_name'])
			->where('last_name', $deliveryData['last_name'])
			->where('post_code', $deliveryData['post_code'])
			->where('district', $deliveryData['district'])
			->where('city', $deliveryData['city'])
			->where('address', $deliveryData['address'])
			->where('phone_number', $deliveryData['phone_number'])
			->where('mobile_tel', $deliveryData['mobile_tel'])
			->where('email', $deliveryData['email'])
			->exists();
		if (!$existsInAddressBook) {
			DeliveryAddress::create($deliveryData);
		}

		// Payment / UserPaymentHistory:
		// 決済は着用日11日前に自動実行されるため、注文時点ではPayment・UserPaymentHistoryを作成しない
		// ChargeScheduledPaymentsCommand で決済成功時に作成される

		//Clear Cart
		Cart::clear();

		// Prepare email data from order details
		$orderDetails = OrderDetail::where('order_id', $order->id)->get();
		$productCodes = [];
		$productPrices = [];
		$optionPrices = [];
		$wearDates = [];
		$rentalPeriods = [];

		foreach ($orderDetails as $detail) {
			$productCodes[] = $detail->product_name;
			$productPrices[] = $detail->price;
			$optionPrices[] = ($detail->safe_pack ?? 0) + ($detail->tabi ?? 0) + ($detail->towel ?? 0);

			// Format wear date
			if ($detail->wear_date) {
				$wearDateFormatted = date('Y/m/d', strtotime($detail->wear_date));
				$wearDates[] = $wearDateFormatted;

				$rentalDates = $this->buildRentalMailDates($detail->wear_date);
				$rentalPeriods[] = $rentalDates['rental_start_date'] . ' ～ ' . $rentalDates['rental_end_date'];
			}
		}

		//Send Email
		$data = $params;
		$data['site'] = url("/");
		$data['code'] = $orderCode;
		$data['shipping_cost'] = "¥" . number_format($totalShipping);
		$data['total_amount'] = "¥" . number_format($cartTotalAmount + $totalShipping);
		$data['payment_method'] = ($paymentMethod == 0) ? "クレジットカード" : "銀行振込";
		$data['payment_status'] = ($paymentMethod == 0) ? "未払い（着用日11日前に自動決済）" : "未払い";
		$data['note'] = '';
		$data['name'] = $user->full_name;
		$data['furigana'] = $user->furigana_name;
		$data['address'] = "〒" . $user->post_code . " " . $user->city . " " . $user->district . " " . $user->address . " " . $user->address2;
		$data['phone_number'] = $user->phone_number;
		$data['email'] = $user->email;
		$data['is_provisional'] = $isProvisionalOrder;
		$data['provisional_expires_at'] = $isProvisionalOrder ? now()->addDays(3)->format('Y年m月d日 H:i') : null;

		// Additional data for provisional order email template
		$data['product_code'] = implode(', ', $productCodes);
		$data['product_price'] = "¥" . number_format(array_sum($productPrices));
		$data['option_price'] = "¥" . number_format(array_sum($optionPrices));
		$data['wearing_date'] = !empty($wearDates) ? implode(', ', $wearDates) : '未定';
		$data['rental_days'] = 5;

		// Calculate dates for rental flow
		if (!empty($wearDates)) {
			$data = array_merge($data, $this->buildRentalMailDates($orderDetails->first()->wear_date));
		} else {
			$data['rental_start_date'] = '';
			$data['rental_end_date'] = '';
			$data['arrival_date'] = '未定';
			$data['shipping_date'] = '未定';
			$data['return_date'] = '未定';
			$data['store_arrival_date'] = '未定';
		}

		$userEmail = $user->email;
		$notifyContent = ['code' => $orderCode];

		try {
			$productNames2 = $cartCollection->pluck('name')->implode('、');
			$notifyMessage = $isProvisionalOrder
				? "仮予約がありました #" . $orderCode . "（" . ($user->full_name ?? '') . " / " . $productNames2 . "）"
				: "新規注文がありました #" . $orderCode . "（" . ($user->full_name ?? '') . " / " . $productNames2 . "）";

			Notify::create([
				'content'      => $notifyMessage,
				'module'       => 'order',
				'item_id'      => $orderCode,
				'item_content' => json_encode($notifyContent),
				'created_at'   => date('Y-m-d H:i:s'),
				'updated_at'   => date('Y-m-d H:i:s'),
			]);
			event(new NotifyEvent());

			// CMS テンプレート用の変数
			$rentalFlow = $isProvisionalOrder
				? $this->buildRentalFlowHtml($data)
				: $this->buildRentalFlowConfirmedHtml($data);
			$templateVars = [
				'full_name'      => $user->full_name,
				'first_name'     => $user->first_name ?? '',
				'last_name'      => $user->last_name ?? '',
				'email'          => $user->email,
				'order_code'     => $orderCode,
				'total_price'    => number_format($cartTotalAmount),
				'payment_method' => ($paymentMethod == 0) ? 'クレジットカード' : '銀行振込',
				'payment_status' => ($paymentMethod == 0) ? '未払い（着用日11日前に自動決済）' : '未払い',
				'wearing_date'   => $data['wearing_date'] ?? '未定',
				'order_detail'   => $this->buildOrderDetailHtml($data),
				'rental_flow'    => $rentalFlow,
				'payment_deadline_days' => (string) config('rental_dates.payment_deadline_days', 11),
				'grand_total'    => number_format($cartTotalAmount),
				'payment_deadline' => (!empty($data['wearing_date']) && $data['wearing_date'] !== '未定')
					? date('Y/m/d', strtotime($orderDetails->first()->wear_date . ' -' . config('rental_dates.payment_deadline_days', 11) . ' days'))
					: '未定',
			];

			// 管理者向けメール（CMS テンプレート）
			$this->sendTemplateEmail(
				'm_order_received',
				config('settings.admin_email'),
				$templateVars
			);
			logger("[Email] Sent admin order email to: " . config('settings.admin_email'));

			// ユーザー向けメール（CMS テンプレート）
			// 本人確認未完了 → 受注確認（仮予約）、本人確認済み → クレカは受注確定 / 振込は受注確認
			if ($isProvisionalOrder) {
				$userSlug = ($paymentMethod == 0) ? 'u_provisional_order_credit' : 'u_provisional_order_bank';
			} else {
				$userSlug = ($paymentMethod == 0) ? 'u_order_confirmed_credit' : 'u_order_confirmed_bank';
			}
			$this->sendTemplateEmail($userSlug, $userEmail, $templateVars);
			logger("[Email] Sent user order email ({$userSlug}) to: " . $userEmail);

			// オーナー商品の場合、オーナーに貸出通知メールを送信
			foreach ($orderDetails as $detail) {
				$detailProduct = Product::find($detail->product_id);
				if ($detailProduct && $detailProduct->isOwnerProduct() && $detailProduct->owner_id && $detailProduct->reward_amount > 0) {
					$ownerUser = User::find($detailProduct->owner_id);
					if ($ownerUser) {
						$this->sendTemplateEmail('email_owner_rental_notify', $ownerUser->email, [
							'owner_name' => $ownerUser->full_name ?? $ownerUser->name,
							'product_name' => $detailProduct->name ?? '',
							'rental_period' => ($data['rental_start_date'] ?? '未定') . ' ～ ' . ($data['rental_end_date'] ?? '未定'),
							'reward_amount' => number_format($detailProduct->reward_amount),
						]);
						logger("[Email] Sent owner rental notify to: " . $ownerUser->email);
					}
				}
			}

		} catch (\Exception $exception) {
			logger($exception->getMessage());
		}

		// 注文作成・商品ステータス更新のトランザクションをコミット
		\DB::commit();

		} catch (\Exception $e) {
			\DB::rollBack();
			logger('Order creation failed: ' . $e->getMessage());
			return response()->json(['errors' => 'ご注文の処理中にエラーが発生しました。もう一度お試しください。'], 500);
		}

		return response()->json([
			'status' => 'success',
			'code' => $orderCode,
			'is_provisional' => $isProvisionalOrder,
			'message' => $isProvisionalOrder
				? '仮予約が完了しました。本人確認書類を提出してください。'
				: 'ご注文ありがとうございます。'
		], 200);
	}

	/**
	 * Get shipping cost by area_id
	 */
	public function getShippingCost(Request $request)
	{
		$prefecture = $request->get('prefecture', '');
		$postalCode = $request->get('postal_code', '');
		$productPrice = $request->get('product_price', 0);

		[$cost, $isSpecial] = $this->computeShippingCost($prefecture, $postalCode, $productPrice);

		return response()->json([
			'shipping_cost' => $cost,
			'is_special_area' => $isSpecial,
			'free_shipping' => $cost === 0,
		]);
	}

	/**
	 * 配送先と商品金額から送料を算出する（信頼できる単一ロジック）。
	 * クライアントから渡される shipping_cost は信用せず、必ずこのメソッドでサーバ側計算する。
	 *
	 * @return array{0:int,1:bool} [送料, 特別地域フラグ]
	 */
	private function computeShippingCost($prefecture, $postalCode, $productPrice): array
	{
		// 1. 郵便番号で離島判定
		$isSpecial = false;
		$remoteIslandEnabled = \App\ShippingSetting::where('key', 'remote_island_enabled')->value('value') === '1';
		if ($remoteIslandEnabled && !empty($postalCode)) {
			$cleanPostal = preg_replace('/[^0-9]/', '', $postalCode);
			if (\App\ShippingRemoteIsland::where('postal_code', $cleanPostal)->exists()) {
				$isSpecial = true;
			}
		}

		// 2. 特別料金の都道府県判定
		if (!$isSpecial && !empty($prefecture)) {
			$prefId = \DB::table('prefectures')->where('name', $prefecture)->value('id');
			if ($prefId && \App\ShippingSpecialPrefecture::where('prefecture_id', $prefId)->exists()) {
				$isSpecial = true;
			}
		}

		// 3. 金額帯に合致する送料レートを取得
		$rate = \App\ShippingRate::where('price_from', '<=', $productPrice)
			->orderBy('price_from', 'desc')
			->first();
		if (!$rate) {
			$rate = \App\ShippingRate::orderBy('price_from', 'asc')->first();
		}

		$cost = $rate ? ($isSpecial ? $rate->special_cost : $rate->normal_cost) : 0;

		return [(int) $cost, $isSpecial];
	}


	/**
	 * 注文詳細の HTML を組み立てる（メールテンプレートの {{ order_detail }} 用）
	 */
	protected function buildOrderDetailHtml(array $data): string
	{
		$html = '■ご注文内容<br><table style="border-collapse: collapse; width: 100%; margin-top: 10px;"><tbody>';
		$rows = [
			['受注番号', $data['code'] ?? ''],
			['ご注文者', ($data['name'] ?? '') . ' 様'],
			['着用予定日', $data['wearing_date'] ?? '未定'],
			['レンタル期間', ($data['rental_start_date'] ?? '') . ' ～ ' . ($data['rental_end_date'] ?? '')],
			['着物番号', $data['product_code'] ?? ''],
			['決済方法', $data['payment_method'] ?? ''],
			['商品価格', $data['product_price'] ?? '¥0'],
			['オプション価格', $data['option_price'] ?? '¥0'],
			['送料', $data['shipping_cost'] ?? '¥0'],
			['合計金額', $data['total_amount'] ?? ''],
		];
		foreach ($rows as $row) {
			$html .= '<tr><td style="padding: 8px 20px; width: 35%;">[' . $row[0] . ']</td>'
				. '<td style="padding: 8px;">' . $row[1] . '</td></tr>';
		}
		$html .= '</tbody></table>';
		return $html;
	}

	/**
	 * レンタルの流れ HTML を組み立てる（メールテンプレートの {{ rental_flow }} 用）
	 */
	protected function buildRentalFlowHtml(array $data): string
	{
		$paymentLabel = ($data['payment_method'] ?? '') === 'クレジットカード'
			? 'お支払い（着用日の11日前にクレジットカード自動決済）'
			: 'お支払い';

		$steps = [
			'【 ご注文確認 】※ご注文は確定していません',
			'ご注文確定',
			$paymentLabel,
			'当店発送予定日：' . ($data['shipping_date'] ?? '未定'),
			'着物到着日：' . ($data['arrival_date'] ?? '未定'),
			'ご着用予定日：' . ($data['wearing_date'] ?? '未定'),
			'返却期日：' . ($data['return_date'] ?? '未定'),
			'当店到着予定日：' . ($data['store_arrival_date'] ?? '未定'),
			'お取引完了',
		];

		$html = '■レンタルの流れ（現在のステータス：【ご注文確認】）<br><br><div style="margin-left: 20px;">';
		foreach ($steps as $i => $step) {
			$html .= '<span style="margin-left: 10px;">' . $step . '</span><br>';
			if ($i < count($steps) - 1) {
				$html .= '<span style="margin-left: 35px;">▼</span><br>';
			}
		}
		$html .= '</div>';
		return $html;
	}

	/**
	 * レンタルの流れ HTML（注文確定パターン）
	 */
	protected function buildRentalFlowConfirmedHtml(array $data): string
	{
		$paymentLabel = ($data['payment_method'] ?? '') === 'クレジットカード'
			? 'お支払い（着用日の11日前にクレジットカード自動決済）'
			: 'お支払い';

		$steps = [
			'ご注文確認',
			'【 ご注文確定 】',
			$paymentLabel,
			'当店発送予定日：' . ($data['shipping_date'] ?? '未定') . ' 頃',
			'着物到着日：' . ($data['arrival_date'] ?? '未定'),
			'ご着用予定日：' . ($data['wearing_date'] ?? '未定'),
			'返却期日：' . ($data['return_date'] ?? '未定'),
			'当店到着予定日：' . ($data['store_arrival_date'] ?? '未定'),
			'お取引完了',
		];

		$html = '■レンタルの流れ（現在のステータス：【ご注文確定】）<br><br><div style="margin-left: 20px;">';
		foreach ($steps as $i => $step) {
			$html .= '<span style="margin-left: 10px;">' . $step . '</span><br>';
			if ($i < count($steps) - 1) {
				$html .= '<span style="margin-left: 35px;">▼</span><br>';
			}
		}
		$html .= '</div>';
		return $html;
	}

	private function buildRentalMailDates($wearDate): array
	{
		$wearingDate = Carbon::parse($wearDate);
		$productDeliveryDays = (int) config('rental_dates.product_delivery_days', 3);
		$storeShippingDays = (int) config('rental_dates.store_shipping_days', 10);
		$returnAfterDays = (int) config('rental_dates.return_after_days', 2);
		$storeArrivalAfterReturnDays = (int) config('rental_dates.store_arrival_after_return_days', 1);
		$defaultRentalNights = (int) config('rental_dates.default_rental_nights', 5);

		$rentalStartDate = $wearingDate->copy()->subDays($productDeliveryDays);
		$rentalEndDate = $rentalStartDate->copy()->addDays($defaultRentalNights);

		return [
			'rental_start_date' => $rentalStartDate->format('Y/m/d'),
			'rental_end_date' => $rentalEndDate->format('Y/m/d'),
			'arrival_date' => $rentalStartDate->format('Y/m/d'),
			'shipping_date' => $wearingDate->copy()->subDays($storeShippingDays)->format('Y/m/d'),
			'return_date' => $wearingDate->copy()->addDays($returnAfterDays)->format('Y/m/d'),
			'store_arrival_date' => $wearingDate->copy()->addDays($returnAfterDays + $storeArrivalAfterReturnDays)->format('Y/m/d'),
		];
	}

	/**
	 * 重複しない注文コードを生成する。
	 * 以前は rand(000,999)（8進数リテラルで実質 rand(0,999)）により桁数の揺れと
	 * 衝突リスクがあった。9桁ゼロ埋めの乱数を一意になるまで再試行する。
	 */
	private function generateUniqueOrderCode(): string
	{
		for ($i = 0; $i < 50; $i++) {
			$orderCode = str_pad((string) random_int(0, 999999999), 9, '0', STR_PAD_LEFT);
			if (!Order::where('code', $orderCode)->exists()) {
				return $orderCode;
			}
		}
		// 通常到達しないが、衝突が続く場合はタイムスタンプ由来で必ず一意にする
		return 'O' . substr((string) (int) (microtime(true) * 1000), -11);
	}

	/**
	 * 注文のブロックデートを登録（着用日±7日）
	 */
	private function registerOrderBlockDates($productId, $wearDate, $orderId)
	{
		$blockBefore = config('rental_dates.block_days_before', 7);
		$blockAfter = config('rental_dates.block_days_after', 50);
		$start = Carbon::parse($wearDate)->subDays($blockBefore);
		$end = Carbon::parse($wearDate)->addDays($blockAfter);
		while ($start->lte($end)) {
			ProductSchedule::firstOrCreate([
				'product_id' => $productId,
				'short_date' => $start->toDateString(),
			], [
				'order_id' => $orderId,
				'full_date' => $start->toDateString() . ' 00:00:00',
				'note' => 'レンタル予約（注文ID:' . $orderId . '）',
				'created_at' => now(),
				'updated_at' => now(),
			]);
			$start->addDay();
		}
	}
}
