<?php

namespace App\Http\Controllers;

use App\ServiceRequest;
use App\Notify;
use App\Events\NotifyEvent;
use App\Traits\SendsTemplateEmail;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Validator;

class ServiceRequestController extends Controller
{
    use SendsTemplateEmail;

    /**
     * ログインユーザーの申請一覧
     */
    public function index()
    {
        $user = Auth::user();
        $requests = ServiceRequest::where('user_id', $user->id)
            ->with('product')
            ->orderBy('id', 'DESC')
            ->get();

        return response()->json($requests);
    }

    /**
     * 申請を送信
     */
    public function store(Request $request)
    {
        $rules = [
            'type' => ['required', 'integer', 'in:0,1,2,3'],
            'content' => ['nullable', 'string', 'max:2000'],
            'product_id' => ['required', 'integer', 'exists:products,id'],
            'delivery_date' => ['nullable', 'date'],
            'return_date' => ['nullable', 'date'],
        ];

        // 一時返却は日付も必須
        if ((int) $request->input('type') === ServiceRequest::TYPE_TEMPORARY_RETURN) {
            $rules['delivery_date'] = ['required', 'date'];
            $rules['return_date'] = ['required', 'date', 'after_or_equal:delivery_date'];
        }

        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }

        $user = Auth::user();
        $productId = $request->input('product_id');
        $type = (int) $request->input('type');
        $deliveryDate = $request->input('delivery_date');
        $returnDate = $request->input('return_date');

        // 同じ商品に対して処理中の申請がある場合は重複を防止
        // 同じタイプの申請のみチェック、一時返却は日付が異なれば複数申請可能
        if ($productId) {
            $existingQuery = ServiceRequest::where('user_id', $user->id)
                ->where('product_id', $productId)
                ->where('type', $type)
                ->whereIn('status', [ServiceRequest::STATUS_PENDING, ServiceRequest::STATUS_IN_PROGRESS]);

            if ($type === ServiceRequest::TYPE_TEMPORARY_RETURN) {
                // 一時返却: 日付範囲が重なる申請のみチェック
                $existingQuery->where(function ($q) use ($deliveryDate, $returnDate) {
                    $q->where('delivery_date', '<=', $returnDate)
                       ->where('return_date', '>=', $deliveryDate);
                });
            }

            $existing = $existingQuery->first();
            if ($existing) {
                if ($type === ServiceRequest::TYPE_TEMPORARY_RETURN) {
                    return response()->json([
                        'errors' => "この商品に対して同じ期間の一時返却申請があります。日程を変更してください。"
                    ], 422);
                }
                return response()->json([
                    'errors' => "この商品に対して処理中の申請（" . ServiceRequest::typeLabel($type) . "）があります。完了後に再度お申し込みください。"
                ], 422);
            }
        }

        // 一時返却: レンタル予約との重複チェック（オーナー商品の場合）
        if ($type === ServiceRequest::TYPE_TEMPORARY_RETURN && $productId && $deliveryDate && $returnDate) {
            $product = \App\Product::find($productId);
            if ($product && (int) $product->type === \App\Product::TYPE_OWNER) {
                // レンタル占有期間: 着用日の前block_days_before日〜後block_days_after日
                $blockBefore = config('rental_dates.block_days_before', 7);
                $blockAfter = config('rental_dates.block_days_after', 50);
                $conflictingOrders = \App\OrderDetail::where('product_id', $productId)
                    ->whereHas('order', function ($q) {
                        $q->whereNotIn('status', [\App\Order::STATUS_CANCELLED]);
                    })
                    ->whereRaw('DATE_SUB(wear_date, INTERVAL ? DAY) <= ?', [$blockBefore, $returnDate])
                    ->whereRaw('DATE_ADD(wear_date, INTERVAL ? DAY) >= ?', [$blockAfter, $deliveryDate])
                    ->pluck('wear_date')
                    ->map(function ($d) {
                        return \Carbon\Carbon::parse($d);
                    })
                    ->sort()
                    ->values();

                if ($conflictingOrders->isNotEmpty()) {
                    $periods = $conflictingOrders->map(function ($wearDate) use ($blockBefore, $blockAfter) {
                        $from = $wearDate->copy()->subDays($blockBefore)->format('Y/m/d');
                        $to = $wearDate->copy()->addDays($blockAfter)->format('Y/m/d');
                        return "{$from}〜{$to}";
                    })->unique()->join('、');
                    return response()->json([
                        'errors' => "指定した期間にレンタル予約（{$periods}）が入っているため、一時返却をお受けできません。日程を変更してください。"
                    ], 422);
                }
            }
        }

        $serviceRequest = ServiceRequest::create([
            'user_id' => $user->id,
            'product_id' => $productId,
            'type' => $type,
            'status' => ServiceRequest::STATUS_PENDING,
            'content' => $request->input('content'),
            'delivery_date' => $deliveryDate,
            'return_date' => $returnDate,
        ]);

        // 一時返却: ブロックデートを自動登録（前後バッファ含む）
        if ($type === ServiceRequest::TYPE_TEMPORARY_RETURN && $productId && $deliveryDate && $returnDate) {
            $blockBefore = config('rental_dates.block_days_before', 7);
            $blockAfter = config('rental_dates.block_days_after', 50);
            $start = \Carbon\Carbon::parse($deliveryDate)->subDays($blockBefore);
            $end = \Carbon\Carbon::parse($returnDate)->addDays($blockAfter);
            while ($start->lte($end)) {
                \App\ProductSchedule::firstOrCreate([
                    'product_id' => $productId,
                    'short_date' => $start->toDateString(),
                ], [
                    'full_date' => $start->toDateString() . ' 00:00:00',
                    'note' => '一時返却（申請ID:' . $serviceRequest->id . '）',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                $start->addDay();
            }
        }

        // 管理者ベル通知
        $typeLabel = ServiceRequest::typeLabel($type);
        $product = $productId ? \App\Product::find($productId) : null;
        $productName = $product ? $product->name : '';
        try {
            Notify::create([
                'content'      => "{$typeLabel}の申請がありました（{$user->full_name} / {$productName}）",
                'module'       => 'service_request',
                'item_id'      => $serviceRequest->id,
                'item_content' => json_encode(['id' => $serviceRequest->id, 'type' => $type]),
                'created_at'   => now(),
                'updated_at'   => now(),
            ]);
            event(new NotifyEvent());
        } catch (\Exception $e) {
            logger("[Notify] Service request notification failed: " . $e->getMessage());
        }

        // 管理者メール通知
        try {
            $this->sendTemplateEmail(
                'm_service_request_received',
                config('settings.admin_email'),
                [
                    'user_name' => $user->full_name ?? $user->name,
                    'request_type' => $typeLabel,
                    'product_name' => $productName,
                    'content' => $request->input('content') ?? '',
                ]
            );
        } catch (\Exception $e) {
            logger("[Email] Service request admin email failed: " . $e->getMessage());
        }

        return response()->json([
            'status' => 'success',
            'request' => $serviceRequest,
        ], 201);
    }
}
