<?php

namespace App\Http\Controllers\Admin;

use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\ProductResourceDetail;
use App\Laravue\Models\User;
use App\ProductCategory;
use App\ProductImage;
use App\ProductSchedule;
use App\ProductSku;
use App\Services\StorageChargeService;
use App\StorageContract;
use App\Traits\SendsTemplateEmail;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use App\Http\Resources\Admin\ProductResource;
use App\Http\Resources\Admin\ProductListResource;
use App\Product;
use App\Keyword;
use App\ProductKeyword;
use Illuminate\Support\Facades\Log;
use Validator;

/**
 * Class ProductController
 *
 * @package App\Http\Controllers
 */
class ProductController extends Controller
{
	use SendsTemplateEmail;

	const ITEM_PER_PAGE = 100;
	
	public function index(Request $request)
	{
		$searchParams = $request->all();
		$list = Product::notDeleted()->with(['owner', 'user', 'category']);
		$limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
		$type = Arr::get($searchParams, 'type', '');
		$keyword = Arr::get($searchParams, 'keyword', '');
		$status = Arr::get($searchParams, 'status', '');
		$categoryId = Arr::get($searchParams, 'category_id', '');
		
		if (!empty($keyword)) {
			$list->where(function ($query) use ($keyword) {
				$query->where('name', 'LIKE', '%' . $keyword . '%')
					->orWhere('id', '=', $keyword)
					->orWhere('slug', 'LIKE', '%' . $keyword . '%')
					->orWhere('sku_storage', 'LIKE', '%' . $keyword . '%')
					->orWhere('storage_cabinet_code', 'LIKE', '%' . $keyword . '%')
					->orWhere('owner_id', '=', $keyword)
					->orWhereHas('category', function ($subQuery) use ($keyword) {
						$subQuery->whereHas('category', function ($categoryQuery) use ($keyword) {
							$categoryQuery->where('name', 'LIKE', '%' . $keyword . '%');
						});
					})
					->orWhereHas('owner', function ($ownerQuery) use ($keyword) {
						$ownerQuery->where('name', 'LIKE', '%' . $keyword . '%')
							->orWhere('full_name', 'LIKE', '%' . $keyword . '%')
							->orWhere('furigana_name', 'LIKE', '%' . $keyword . '%');
					});
			});
		}
		
		if ($type != '') {
			// type はカンマ区切りで複数指定可（例: "0,2" → オーナー＋シェアリング商品）
			if (is_string($type) && strpos($type, ',') !== false) {
				$list->whereIn('type', array_map('intval', explode(',', $type)));
			} else {
				$list->where('type', $type);
			}
		}

		if ($status != '') {
			$list->where('is_activated', $status);
		}
		
		if (!empty($categoryId)) {
			$finalCategoryId = is_array($categoryId) ? end($categoryId) : $categoryId;
			if (!empty($finalCategoryId)) {
				$list->whereHas('category', function ($query) use ($finalCategoryId) {
					$query->where('category_id', $finalCategoryId);
				});
			}
		}
		
		$list->orderBy('id', 'DESC');
		
		return ProductListResource::collection($list->paginate($limit));
	}
	
	public function all(Request $request)
	{
		$searchParams = $request->all();
		$limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
		$list = Product::select('id', 'name', 'slug')->notDeleted()->orderBy('position')->orderBy('id');
		
		return ProductResource::collection($list->paginate($limit));
	}
	
	public function available()
	{
		$list = Product::select('id', 'name')->notDeleted()->activated()->orderBy('position')->orderBy('id');
		
		return ProductResource::collection($list->get());
	}
	
	public function show($id = 0)
	{
		$product = Product::notDeleted()->where('id', $id)->first();
		if (!isset($product)) return response()->json(['errors' => __('messages.product_not_valid')], 403);
		
		return new ProductResourceDetail($product);
	}
	
	public function store(Request $request)
	{
		$validator = Validator::make($request->all(), [
			'name'          => ['required'],
			'sku_storage'   => ['required'],
			'sku_codes'     => ['required'],
			'type'          => ['required'],
			'default_price' => ['required'],
			'category'      => ['required'],
			'rank'          => ['required'],
			'size'          => ['required'],
			'hip'           => ['required'],
			'is_activated'  => ['required']
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$params = $request->all();
		
		// Validate sku_storage unique
		$existingSkuStorage = Product::notDeleted()->where('sku_storage', trim($params['sku_storage']))->first();
		if ($existingSkuStorage) {
			return response()->json(['errors' => __('messages.sku_storage_already_exists')], 403);
		}
		
		// Validate SKU codes
		if (isset($params['sku_codes']) && is_array($params['sku_codes'])) {
			$skuCodes = array_column($params['sku_codes'], 'code');
			$skuCodes = array_filter($skuCodes); // Remove empty codes
			
			if (empty($skuCodes)) {
				return response()->json(['errors' => __('messages.sku_codes_required')], 403);
			}
			
			// Check for duplicates
			if (count($skuCodes) !== count(array_unique($skuCodes))) {
				return response()->json(['errors' => __('messages.duplicate_sku_codes')], 403);
			}
			
			// Check if any SKU code already exists
			foreach ($skuCodes as $code) {
				$fullSku = trim($params['sku_storage']) . '-' . $code;
				$existingSku = Product::notDeleted()->where('sku', $fullSku)->first();
				if ($existingSku) {
					return response()->json(['errors' => __('messages.sku_already_exists', ['sku' => $fullSku])], 403);
				}
			}
		}
		
		$thumb = (isset($params['image']) && $params['image'] != '') ? $params['image'] : 'no-image.png';
		if ($thumb == 'no-image.png' && isset($params['sliders'][0])) {
			$thumb = $params['sliders'][0];
		}
		
		// Always generate preview code for new products
		$previewCode = md5(uniqid(rand(), true) . time());
		
		$mainSku = trim($params['sku_storage']);
		if (isset($params['sku_codes']) && is_array($params['sku_codes']) && !empty($params['sku_codes'])) {
			$firstSkuCode = $params['sku_codes'][0]['code'];
			if (!empty($firstSkuCode)) $mainSku .= '-' . $firstSkuCode;
		}
		
		$product = Product::create([
			'name'                  => trim($params['name']),
			'sku'                   => $mainSku,
			'sku_storage'           => trim($params['sku_storage']),
			'slug'                  => Helper::slug(trim($params['slug'])),
			'type'                  => $params['type'],
			'default_price'         => $params['default_price'],
			'reward_amount'         => isset($params['reward_amount']) ? $params['reward_amount'] : null,
			'regular_price_from'    => 2000,
			'discount'              => (isset($params['discount']) && $params['discount'] != "") ? $params['discount'] : null,
			'discount_type'         => (isset($params['discount_type']) && $params['discount_type'] === 1) ? 1 : 0,
			'image'                 => $thumb,
			'tryon_model_image'     => isset($params['tryon_model_image']) ? $params['tryon_model_image'] : null,
			'gender'                => $params['gender'],
			'material'              => $params['material'],
			'rank'                  => $params['rank'],
			'size'                  => $params['size'],
			'height'                => $params['height'],
			'sleeve'                => $params['sleeve'],
			'sleeve_length'         => $params['sleeve_length'],
			'hip'                   => $params['hip'],
			'primary_width'         => $params['front_width'],
			'second_width'          => $params['rear_width'],
			'storage_date'          => date('Y-m-d'), //$params['storage_date'],
			'storage_cabinet_code'  => isset($params['storage_cabinet_code']) ? trim($params['storage_cabinet_code']) : null,
			'owner_id'              => isset($params['owner_id']) ? $params['owner_id'] : null,
			'undergarment_length'   => $params['undergarment_length'],
			'description'           => $params['description'],
			'note'                  => $params['note'],
			'preview'               => $previewCode,
			'is_cleaning_service'   => ($params['is_cleaning_service'] == 1) ? 1 : 0,
			'is_storage_period'     => ($params['is_storage_period'] == 1) ? 1 : 0,
			'order_status'          => isset($params['order_status']) ? (int)$params['order_status'] : 0,
			'is_available_in_stock' => ($params['is_available_in_stock'] === true) ? 1 : 0,
			'is_allow_faceswap'     => ($params['is_allow_faceswap'] === true) ? 1 : 0,
			'is_activated'          => ($params['is_activated'] === true) ? 1 : 0,
			'created_at'            => date('Y-m-d H:i:s'),
			'updated_at'            => date('Y-m-d H:i:s')
		]);
		
		//Images
		foreach ($params['sliders'] as $item) {
			ProductImage::create([
				'product_id' => $product->id,
				'name'       => $item,
				'file_name'  => $item,
				'position'   => 0,
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s')
			]);
		}
		
		//Category
		foreach ($params['category'] as $item) {
			ProductCategory::create([
				'product_id'  => $product->id,
				'category_id' => $item,
				'created_at'  => date('Y-m-d H:i:s'),
				'updated_at'  => date('Y-m-d H:i:s')
			]);
		}
		
		//Schedule
		foreach ($params['schedule'] as $item) {
			ProductSchedule::create([
				'product_id' => $product->id,
				'short_date' => $item['id'],
				'full_date'  => $item['id'] . ' 00:00:00',
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s')
			]);
		}
		
		//Keyword
		$keywords = [];
		foreach ($params['keyword'] as $item) {
			$tag = trim($item['text']);
			$checkKeyword = Keyword::where('is_deleted', 0)
				->where(function ($query) use ($tag) {
					$query->where('name', $tag)
						->orWhere('name', strtolower($tag))
						->orWhere('name', strtoupper($tag))
						->orWhere('name', ucfirst($tag));
				})->first();
			
			if (!$checkKeyword) {
				$checkKeyword = Keyword::create([
					'name'         => $tag,
					'is_activated' => true,
					'is_deleted'   => false,
					'created_at'   => date('Y-m-d H:i:s'),
					'updated_at'   => date('Y-m-d H:i:s'),
				]);
			}
			
			$keywords[] = [
				'keyword_id' => $checkKeyword->id,
				'product_id' => $product->id,
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s'),
			];
		}
		if (count($keywords) > 0) ProductKeyword::insert($keywords);
		
		//SKU Codes
		if (isset($params['sku_codes']) && is_array($params['sku_codes'])) {
			foreach ($params['sku_codes'] as $skuData) {
				if (!empty($skuData['code'])) {
					ProductSku::create([
						'product_id' => $product->id,
						'code'       => $skuData['code'],
						'created_at' => date('Y-m-d H:i:s'),
						'updated_at' => date('Y-m-d H:i:s')
					]);
				}
			}
		}

		// 保管商品の場合: 保管契約を作成し課金を実行
		// ※ owner_id は保管商品の場合「保管ユーザー（課金対象）」、オーナー商品の場合「オーナー」を指す
		$storageContractResult = null;
		if ((int)$params['type'] === Product::TYPE_STORAGE && isset($params['owner_id'])) {
			$storageStartDate = $params['storage_start_date'] ?? null;
			$storageUser = User::find($params['owner_id']);
			$skipInitialCharge = !empty($params['skip_initial_charge']);
			if (!$storageStartDate) {
				$storageContractResult = [
					'contract_id' => null,
					'charged' => false,
					'error' => '保管開始日が未指定のため、保管契約を作成できませんでした。',
				];
			} elseif (!$storageUser) {
				$storageContractResult = [
					'contract_id' => null,
					'charged' => false,
					'error' => '保管ユーザーが見つからないため、保管契約を作成できませんでした。',
				];
			} else {
				try {
					$storageChargeService = new StorageChargeService();
					$startDate = \Carbon\Carbon::parse($storageStartDate);
					if ($skipInitialCharge) {
						// 既にオフラインで受領済み → 初回課金をスキップして契約のみ作成（カード不要）
						$contract = $storageChargeService->createContractWithoutCharge($product, $storageUser, $storageStartDate);
						$storageContractResult = [
							'contract_id' => $contract->id,
							'charged' => false,
							'skipped' => true,
						];
					} elseif (!$storageUser->payjp_customer_id) {
						// 課金が必要だがカード未登録 → 契約は作成せずエラー（初回スキップを使うか、カード登録が必要）
						$storageContractResult = [
							'contract_id' => null,
							'charged' => false,
							'error' => 'カード未登録のため保管料を課金できません。カード登録後に再登録するか、初回課金スキップをご利用ください。',
						];
					} elseif ($startDate->isAfter(now()->startOfDay())) {
						// 保管開始日が未来 → 契約のみ作成、課金は自動更新コマンドで実行
						$contract = $storageChargeService->createContractOnly($product, $storageUser, $storageStartDate);
						$storageContractResult = [
							'contract_id' => $contract->id,
							'charged' => false,
							'scheduled' => true,
						];
					} else {
						// 保管開始日が今日以前 → 即時課金
						$contract = $storageChargeService->createContractAndCharge($product, $storageUser, $storageStartDate);
						$storageContractResult = [
							'contract_id' => $contract->id,
							'charged' => true,
						];
					}
				} catch (\Exception $e) {
					Log::error("ProductController: 保管契約作成/課金失敗 product_id={$product->id}, error={$e->getMessage()}");
					$storageContractResult = [
						'contract_id' => null,
						'charged' => false,
						'error' => $e->getMessage(),
					];
				}
			}
		}

		return response()->json([
			'status'  => 'success',
			'id'      => $product->id,
			'preview' => $previewCode,
			'storage_contract' => $storageContractResult,
		], 200);
	}

	public function update(Request $request, $id = 0)
	{
		$validator = Validator::make($request->all(), [
			'name'          => ['required'],
			'sku_storage'   => ['required'],
			'sku_codes'     => ['required'],
			'type'          => ['required'],
			'default_price' => ['required'],
			'category'      => ['required'],
			'rank'          => ['required'],
			'size'          => ['required'],
			'hip'           => ['required'],
			'is_activated'  => ['required']
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$product = Product::notDeleted()->where('id', $id)->first();
		if (!isset($product)) return response()->json(['errors' => __('messages.product_not_valid')], 403);
		$params = $request->all();

		// タイプ変更を検知するために旧タイプを保存
		$oldType = (int)$product->type;
		$newType = (int)$params['type'];

		// Validate sku_storage unique (only if changed)
		if (trim($params['sku_storage']) !== $product->sku_storage) {
			$existingSkuStorage = Product::notDeleted()
				->where('sku_storage', trim($params['sku_storage']))
				->where('id', '!=', $id)
				->first();
			if ($existingSkuStorage) {
				return response()->json(['errors' => __('messages.sku_storage_already_exists')], 403);
			}
		}
		
		// Validate SKU codes
		if (isset($params['sku_codes']) && is_array($params['sku_codes'])) {
			$skuCodes = array_column($params['sku_codes'], 'code');
			$skuCodes = array_filter($skuCodes); // Remove empty codes
			
			if (empty($skuCodes)) {
				return response()->json(['errors' => __('messages.sku_codes_required')], 403);
			}
			
			// Check for duplicates
			if (count($skuCodes) !== count(array_unique($skuCodes))) {
				return response()->json(['errors' => __('messages.duplicate_sku_codes')], 403);
			}
			
			// Check if any SKU code already exists (excluding current product SKUs)
			foreach ($skuCodes as $code) {
				$fullSku = trim($params['sku_storage']) . '-' . $code;
				$existingSku = Product::notDeleted()
					->where('sku', $fullSku)
					->where('id', '!=', $id)
					->first();
				if ($existingSku) {
					return response()->json(['errors' => __('messages.sku_already_exists', ['sku' => $fullSku])], 403);
				}
			}
		}
		
		$thumb = (isset($params['image']) && $params['image'] != '') ? $params['image'] : 'no-image.png';
		if ($thumb == 'no-image.png' && isset($params['sliders'][0])) {
			$thumb = $params['sliders'][0];
		}
		
		// Generate preview code
		$previewCode = md5(uniqid(rand(), true) . time());
		$storageDateDefault = Carbon::parse($product->created_at)->format('Y-m-d');
		
		$mainSku = trim($params['sku_storage']);
		if (isset($params['sku_codes']) && is_array($params['sku_codes']) && !empty($params['sku_codes'])) {
			$firstSkuCode = $params['sku_codes'][0]['code'];
			if (!empty($firstSkuCode)) $mainSku .= '-' . $firstSkuCode;
		}
		
		$product->update([
			'name'                  => trim($params['name']),
			'sku'                   => $mainSku,
			'sku_storage'           => trim($params['sku_storage']),
			'slug'                  => Helper::slug(trim($params['slug'])),
			'type'                  => $params['type'],
			'default_price'         => $params['default_price'],
			'reward_amount'         => isset($params['reward_amount']) ? $params['reward_amount'] : null,
			'regular_price_from'    => 2000,
			'discount'              => (isset($params['discount']) && $params['discount'] != "") ? $params['discount'] : null,
			'discount_type'         => (isset($params['discount_type']) && $params['discount_type'] === 1) ? 1 : 0,
			'image'                 => $thumb,
			'tryon_model_image'     => isset($params['tryon_model_image']) ? $params['tryon_model_image'] : null,
			'gender'                => $params['gender'],
			'material'              => $params['material'],
			'rank'                  => $params['rank'],
			'size'                  => $params['size'],
			'height'                => $params['height'],
			'sleeve'                => $params['sleeve'],
			'sleeve_length'         => $params['sleeve_length'],
			'hip'                   => $params['hip'],
			'primary_width'         => $params['front_width'],
			'second_width'          => $params['rear_width'],
			'storage_date'          => (isset($params['storage_date']) && $params['storage_date'] != null && $params['storage_date'] != "") ? $params['storage_date'] : $storageDateDefault,
			'storage_cabinet_code'  => isset($params['storage_cabinet_code']) ? trim($params['storage_cabinet_code']) : null,
			'owner_id'              => isset($params['owner_id']) ? $params['owner_id'] : null,
			'undergarment_length'   => $params['undergarment_length'],
			'description'           => $params['description'],
			'note'                  => $params['note'],
			'preview'               => $previewCode,
			'is_cleaning_service'   => ($params['is_cleaning_service'] == 1) ? 1 : 0,
			'is_storage_period'     => ($params['is_storage_period'] == 1) ? 1 : 0,
			'order_status'          => isset($params['order_status']) ? (int)$params['order_status'] : 0,
			'is_available_in_stock' => ($params['is_available_in_stock'] === true) ? 1 : 0,
			'is_allow_faceswap'     => ($params['is_allow_faceswap'] === true) ? 1 : 0,
			'is_activated'          => ($params['is_activated'] === true) ? 1 : 0,
			'updated_at'            => date('Y-m-d H:i:s')
		]);
		
		//Images
		ProductImage::where('product_id', $product->id)->delete();
		foreach ($params['sliders'] as $item) {
			ProductImage::create([
				'product_id' => $product->id,
				'name'       => $item,
				'file_name'  => $item,
				'position'   => 0,
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s')
			]);
		}
		
		//Category
		ProductCategory::where('product_id', $product->id)->delete();
		foreach ($params['category'] as $item) {
			ProductCategory::create([
				'product_id'  => $product->id,
				'category_id' => $item,
				'created_at'  => date('Y-m-d H:i:s'),
				'updated_at'  => date('Y-m-d H:i:s')
			]);
		}
		
		//Schedule（差分処理：追加・削除のみ実行）
		$newDates = array_column($params['schedule'], 'id');
		$existingDates = ProductSchedule::where('product_id', $product->id)
			->pluck('short_date')
			->map(function ($d) { return (string) $d; })
			->toArray();

		// 削除：既存にあるがカレンダーから外された日
		$toDelete = array_diff($existingDates, $newDates);
		if (!empty($toDelete)) {
			ProductSchedule::where('product_id', $product->id)
				->whereIn('short_date', $toDelete)
				->delete();
		}

		// 追加：カレンダーにあるが未登録の日
		$toAdd = array_diff($newDates, $existingDates);
		foreach ($toAdd as $date) {
			ProductSchedule::create([
				'product_id' => $product->id,
				'short_date' => $date,
				'full_date'  => $date . ' 00:00:00',
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s')
			]);
		}
		
		//Keyword
		$keywords = [];
		ProductKeyword::where('product_id', $product->id)->delete();
		foreach ($params['keyword'] as $item) {
			$tag = trim($item['text']);
			$checkKeyword = Keyword::where('is_deleted', 0)
				->where(function ($query) use ($tag) {
					$query->where('name', $tag)
						->orWhere('name', strtolower($tag))
						->orWhere('name', strtoupper($tag))
						->orWhere('name', ucfirst($tag));
				})->first();
			
			if (!$checkKeyword) {
				$checkKeyword = Keyword::create([
					'name'         => $tag,
					'is_activated' => true,
					'is_deleted'   => false,
					'created_at'   => date('Y-m-d H:i:s'),
					'updated_at'   => date('Y-m-d H:i:s'),
				]);
			}
			
			$keywords[] = [
				'keyword_id' => $checkKeyword->id,
				'product_id' => $product->id,
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s'),
			];
		}
		if (count($keywords) > 0) ProductKeyword::insert($keywords);
		
		//SKU Codes
		ProductSku::where('product_id', $product->id)->delete();
		if (isset($params['sku_codes']) && is_array($params['sku_codes'])) {
			foreach ($params['sku_codes'] as $skuData) {
				if (!empty($skuData['code'])) {
					ProductSku::create([
						'product_id' => $product->id,
						'code'       => $skuData['code'],
						'created_at' => date('Y-m-d H:i:s'),
						'updated_at' => date('Y-m-d H:i:s')
					]);
				}
			}
		}

		// タイプ変更時の契約連動
		$typeChangeResult = null;
		if ($oldType !== $newType) {
			$typeChangeResult = $this->handleTypeChange($product, $oldType, $newType, $params);
		}

		// 保管商品で保管契約が未作成の場合: 保管契約を作成（必要に応じて課金）
		// ※ 本番未反映のため既存契約との整合性は考慮不要。type 変更で handleTypeChange が
		//    既に契約を作成している場合はスキップ（contract_created=true で判定）。
		$storageContractResult = null;
		$createdByTypeChange = is_array($typeChangeResult) && !empty($typeChangeResult['contract_created']);
		if ($newType === Product::TYPE_STORAGE && !$createdByTypeChange && isset($params['owner_id'])) {
			$existingContract = StorageContract::where('product_id', $product->id)
				->where('status', StorageContract::STATUS_ACTIVE)
				->first();
			$storageStartDate = $params['storage_start_date'] ?? null;
			if (!$existingContract && $storageStartDate) {
				$storageUser = User::find($params['owner_id']);
				$skipInitialCharge = !empty($params['skip_initial_charge']);
				if (!$storageUser) {
					$storageContractResult = [
						'contract_id' => null,
						'charged' => false,
						'error' => '保管ユーザーが見つからないため、保管契約を作成できませんでした。',
					];
				} else {
					try {
						$storageChargeService = new StorageChargeService();
						$startDate = Carbon::parse($storageStartDate);
						if ($skipInitialCharge) {
							// 初回課金スキップ（オフライン受領済み）はカード不要で契約のみ作成
							$contract = $storageChargeService->createContractWithoutCharge($product, $storageUser, $storageStartDate);
							$storageContractResult = [
								'contract_id' => $contract->id,
								'charged' => false,
								'skipped' => true,
							];
						} elseif (!$storageUser->payjp_customer_id) {
							$storageContractResult = [
								'contract_id' => null,
								'charged' => false,
								'error' => 'カード未登録のため保管料を課金できません。カード登録後に再登録するか、初回課金スキップをご利用ください。',
							];
						} elseif ($startDate->isAfter(now()->startOfDay())) {
							$contract = $storageChargeService->createContractOnly($product, $storageUser, $storageStartDate);
							$storageContractResult = [
								'contract_id' => $contract->id,
								'charged' => false,
								'scheduled' => true,
							];
						} else {
							$contract = $storageChargeService->createContractAndCharge($product, $storageUser, $storageStartDate);
							$storageContractResult = [
								'contract_id' => $contract->id,
								'charged' => true,
							];
						}
					} catch (\Exception $e) {
						Log::error("ProductController: 保管契約作成失敗 product_id={$product->id}, error={$e->getMessage()}");
						$storageContractResult = [
							'contract_id' => null,
							'charged' => false,
							'error' => $e->getMessage(),
						];
					}
				}
			}
		}

		return response()->json([
			'status'  => 'success',
			'id'      => $product->id,
			'preview' => $previewCode,
			'type_change' => $typeChangeResult,
			'storage_contract' => $storageContractResult,
		], 200);
	}
	
	public function updateOrderStatus(Request $request, $id = 0)
	{
		$validator = Validator::make($request->all(), [
			'order_status' => ['required'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$product = Product::notDeleted()->where('id', $id)->first();
		if (!isset($product)) return response()->json(['errors' => __('messages.product_not_valid')], 403);
		$params = $request->all();

		$oldOrderStatus = $product->order_status;
		$newOrderStatus = isset($params['order_status']) ? (int)$params['order_status'] : 0;

		$product->update([
			'order_status' => $newOrderStatus,
			'updated_at'   => date('Y-m-d H:i:s')
		]);

		// 一時返却中(5)への変更時にメール送信
		if ($newOrderStatus === Product::ORDER_STATUS_TEMPORARY_RETURN && $oldOrderStatus !== Product::ORDER_STATUS_TEMPORARY_RETURN) {
			$this->sendProductStatusEmail($product, 'email_temp_return_shipped');
		}

		return response()->json([
			'status' => 'success',
			'id'     => $product->id
		], 200);
	}
	
	public function destroy($id = 0)
	{
		$product = Product::notDeleted()->where('id', $id)->first();
		if (!isset($product)) response()->json(['error' => __('messages.cannot_delete_product')], 403);
		
		try {
			$product->update(['is_deleted' => true]);
		} catch (\Exception $ex) {
			response()->json(['error' => $ex->getMessage()], 403);
		}
		
		return response()->json(null, 204);
	}
	
	public function destroyMultiple(Request $request)
	{
		$validator = Validator::make($request->all(), ['ids' => 'required']);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$listIds = $request->get('ids', []);
		$products = Product::notDeleted()->whereIn('id', $listIds)->get();
		if ($products->count() <= 0) response()->json(['error' => __('messages.product_is_invalid')], 403);
		try {
			Product::notDeleted()->whereIn('id', $listIds)->update(['is_deleted' => true]);
		} catch (\Exception $ex) {
			response()->json(['error' => $ex->getMessage()], 403);
		}
		
		return response()->json(null, 204);
	}
	
	public function updateMultiple(Request $request)
	{
		$validator = Validator::make($request->all(), ['ids' => 'required|array']);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);

		$params = $request->all();
		$ids = $params['ids'];
		$updateData = [];

		$allowedFields = [
			'default_price', 'reward_amount', 'discount', 'discount_type',
			'scene_id', 'rank', 'order_status', 'is_activated', 'is_allow_faceswap',
		];

		foreach ($allowedFields as $field) {
			if (isset($params[$field]) && $params[$field] !== '' && $params[$field] !== null) {
				$updateData[$field] = $params[$field];
			}
		}

		if (!empty($updateData)) {
			$updateData['updated_at'] = date('Y-m-d H:i:s');
			Product::whereIn('id', $ids)->update($updateData);
		}

		// Update categories if provided
		if (isset($params['category']) && is_array($params['category']) && count($params['category']) > 0) {
			foreach ($ids as $id) {
				ProductCategory::where('product_id', $id)->delete();
				foreach ($params['category'] as $categoryId) {
					ProductCategory::create(['product_id' => $id, 'category_id' => $categoryId]);
				}
			}
		}

		// Update colors if provided
		if (isset($params['color']) && is_array($params['color']) && count($params['color']) > 0) {
			foreach ($ids as $id) {
				ProductColor::where('product_id', $id)->delete();
				foreach ($params['color'] as $colorId) {
					ProductColor::create(['product_id' => $id, 'color_id' => $colorId]);
				}
			}
		}

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

	public function activateMultiple(Request $request)
	{
		$validator = Validator::make($request->all(), ['ids' => 'required']);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$listIds = $request->get('ids', []);
		$products = Product::notDeleted()->whereIn('id', $listIds)->get();
		if ($products->count() <= 0) response()->json(['error' => __('messages.product_is_invalid')], 403);
		try {
			Product::notDeleted()->whereIn('id', $listIds)->update(['is_activated' => true]);
		} catch (\Exception $ex) {
			response()->json(['error' => $ex->getMessage()], 403);
		}
		
		return response()->json(null, 204);
	}
	
	public function deactivateMultiple(Request $request)
	{
		$validator = Validator::make($request->all(), ['ids' => 'required']);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$listIds = $request->get('ids', []);
		$products = Product::notDeleted()->whereIn('id', $listIds)->get();
		if ($products->count() <= 0) response()->json(['error' => __('messages.product_is_invalid')], 403);
		try {
			Product::notDeleted()->whereIn('id', $listIds)->update(['is_activated' => false]);
		} catch (\Exception $ex) {
			response()->json(['error' => $ex->getMessage()], 403);
		}
		
		return response()->json(null, 204);
	}
	
	public function getNextSku(Request $request)
	{
		$skuStorage = $request->get('sku_storage');
		if (empty($skuStorage)) {
			return response()->json(['errors' => __('messages.sku_storage_required')], 403);
		}
		
		// Tìm SKU có prefix giống và lấy số lớn nhất
		$latestProduct = Product::notDeleted()
			->where('sku', 'LIKE', $skuStorage . '-%')
			->orderByRaw('CAST(SUBSTRING(sku, LENGTH(?) + 2) AS UNSIGNED) DESC', [$skuStorage])
			->first();
		
		$nextNumber = 1;
		if ($latestProduct) {
			// Lấy số cuối từ SKU (ví dụ: KIM-001-01 -> 01)
			$skuParts = explode('-', $latestProduct->sku);
			$lastNumber = end($skuParts);
			if (is_numeric($lastNumber)) {
				$nextNumber = intval($lastNumber) + 1;
			}
		}
		
		// Kiểm tra đã có tối đa 6 SKU con chưa
		$existingCount = Product::notDeleted()
			->where('sku', 'LIKE', $skuStorage . '-%')
			->count();
		
		if ($existingCount >= 6) {
			return response()->json([
				'status'         => 'error',
				'next_sku'       => null,
				'full_sku'       => null,
				'existing_count' => null,
				'message'        => __('messages.sku_storage_max_children', ['storage' => $skuStorage])
			]);
		}
		
		$nextSku = sprintf('%02d', $nextNumber);
		
		return response()->json([
			'status'         => 'success',
			'next_sku'       => $nextSku,
			'full_sku'       => $skuStorage . '-' . $nextSku,
			'existing_count' => $existingCount,
			'message'        => 'success'
		]);
	}
	
	/**
	 * 商品タイプ変更時の契約連動処理
	 */
	private function handleTypeChange(Product $product, int $oldType, int $newType, array $params): array
	{
		$result = ['old_type' => $oldType, 'new_type' => $newType];
		$ownerUser = $product->owner_id ? User::find($product->owner_id) : null;

		// 保管→オーナー（出品承認）: 保管契約を終了
		if ($oldType === Product::TYPE_STORAGE && $newType === Product::TYPE_OWNER) {
			$contract = StorageContract::where('product_id', $product->id)
				->where('status', StorageContract::STATUS_ACTIVE)
				->first();
			if ($contract) {
				$storageChargeService = new StorageChargeService();
				$storageChargeService->terminateContract($contract);
				$result['contract_terminated'] = true;
			}

			// 出品承認メールは申請ステータス完了時に送信（Admin\ServiceRequestController）
		}

		// オーナー→保管（出品停止）: 新規保管契約作成・課金
		if ($oldType === Product::TYPE_OWNER && $newType === Product::TYPE_STORAGE) {
			$storageStartDate = $params['storage_start_date'] ?? now()->toDateString();

			if (!$ownerUser) {
				$result['contract_created'] = false;
				$result['error'] = '保管ユーザーが見つからないため、保管契約を作成できませんでした。';
			} else {
				try {
					$storageChargeService = new StorageChargeService();
					$startDate = \Carbon\Carbon::parse($storageStartDate);
					$skipInitialCharge = !empty($params['skip_initial_charge']);
					if ($skipInitialCharge) {
						// 初回課金スキップ（オフライン受領済み）はカード不要で契約のみ作成
						$contract = $storageChargeService->createContractWithoutCharge($product, $ownerUser, $storageStartDate);
						$result['contract_created'] = true;
						$result['contract_id'] = $contract->id;
					} elseif (!$ownerUser->payjp_customer_id) {
						$result['contract_created'] = false;
						$result['error'] = 'カード未登録のため保管料を課金できません。カード登録後に再登録するか、初回課金スキップをご利用ください。';
					} else {
						if ($startDate->isAfter(now()->startOfDay())) {
							$contract = $storageChargeService->createContractOnly($product, $ownerUser, $storageStartDate);
						} else {
							$contract = $storageChargeService->createContractAndCharge($product, $ownerUser, $storageStartDate);
						}
						$result['contract_created'] = true;
						$result['contract_id'] = $contract->id;
					}
				} catch (\Exception $e) {
					Log::error("ProductController: 出品停止時の保管契約作成失敗 product_id={$product->id}, error={$e->getMessage()}");
					$result['contract_created'] = false;
					$result['error'] = $e->getMessage();
				}
			}

			// 出品停止承認メールは申請ステータス完了時に送信（Admin\ServiceRequestController）
		}

		return $result;
	}

	private function generateSku($length = 8)
	{
		$characters = '0123456789abcdefghijklmnopqrs092u3tuvwxyzaskdhfhf9882323ABCDEFGHIJKLMNksadf9044OPQRSTUVWXYZ';
		$charactersLength = strlen($characters);
		$randomString = '';
		for ($i = 0; $i < $length; $i++) {
			$randomString .= $characters[rand(0, $charactersLength - 1)];
		}

		return $randomString;
	}

	/**
	 * 商品のオーナーまたは保管ユーザーにメール送信
	 */
	private function sendProductStatusEmail(Product $product, string $emailSlug): void
	{
		try {
			$user = $product->owner_id ? User::find($product->owner_id) : null;
			if (!$user) return;

			$this->sendTemplateEmail($emailSlug, $user->email, [
				'user_name' => $user->full_name ?? $user->name,
				'product_name' => $product->name ?? '',
			]);
		} catch (\Exception $e) {
			Log::warning("ProductController: メール送信失敗 product_id={$product->id}, slug={$emailSlug}, error={$e->getMessage()}");
		}
	}
}
