<?php

namespace App\Http\Controllers;

use App\Http\Traits\AuthenticatesUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Artisan;
use Exception;
use function redirect;
use Carbon\Carbon;

class RegularContractCreateController extends Controller
{
    use AuthenticatesUser;

    /**
     * 駐輪場選択画面を表示
     * 
     * @param Request $request
     * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
     */
    public function show(Request $request)
    {
        if ($redirect = $this->handleSessionExpired('駐輪場選択')) {
            return $redirect;
        }

        $userId = session('user_id');
        $user = DB::table('user')->where('user_id', $userId)->first();

        // マルチテナント対応のため、運営元情報をセッションから取得
        $management = session('management');
        if (!$management) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 運営元情報が見つからない user_id=" . $userId);
            abort(404);
        }

        // 検索条件・ページング取得
        $cityId = $request->input('city_id');
        $stationName = $request->input('station_neighbor_station');
        $parkId = $request->input('park_id');
        $page = (int)$request->input('page', 1);
        $perPage = 10;

        // ルート名で画面種別判定（新規定期契約 or 駐輪場検索）
        $isRegularContract = $request->route()->getName() === 'regular_contract.create';
        $activeMenu = $isRegularContract ? 'SWC-8-1' : 'SWC-10-1';

        // マスタデータ取得（運営元フィルタ適用）
        $cities = $this->getCitiesList($management->management_id);
        $stations = $this->getStationsList($management->management_id);
        $parks = $this->getParksList($management->management_id);

        // 運営元が取り扱う車種一覧を取得
        $availableVehicles = $this->getAvailableVehicles($management->management_id);

        // 駐輪場テーブルデータ取得（検索・ページング、運営元フィルタ適用）
        $parksTableData = $this->getParksTableData($management->management_id, $cityId, $stationName, $parkId, $page, $perPage);

        // zone・reserve マスタ取得（運営元フィルタ適用）
        $zones = $this->getZonesByParkId($management->management_id);
        $reserve = $this->getReserveByParkId($management->management_id);

        // 駐輪場ごとの更新可能期間取得（運営元フィルタ適用）
        $parkGracePeriods = $this->getParkGracePeriods($management->management_id);

        // 駐輪場ごと・車種ごとの状態を事前計算
        $parksTableData['data'] = $this->calculateVehicleStatus(
            $parksTableData['data'],
            $zones,
            $reserve,
            $parkGracePeriods,
            $availableVehicles
        );

        // アクセスログ記録
        $screenName = $isRegularContract ? '新規定期契約登録' : '駐輪場検索';
        \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " {$screenName}画面アクセス user_id=" . $userId . ", management_id=" . $management->management_id . ", city_id=" . ($cityId ?? 'null') . ", park_id=" . ($parkId ?? 'null'));

        return view('regular_contract.create', [
            'active_menu' => $activeMenu,
            'user_name' => $user->user_name ?? '',
            'cities' => $cities,
            'stations' => $stations,
            'parks' => $parks,
            'parks_table' => $parksTableData['data'],
            'parks_table_total' => $parksTableData['total'],
            'parks_table_page' => $page,
            'parks_table_perPage' => $perPage,
            'available_vehicles' => $availableVehicles,
            'reserve' => $reserve,
            'isRegularContract' => $isRegularContract,
        ]);
    }

    /**
     * 市町村一覧取得（運営元フィルタ適用）
     * マルチテナント対応のため、運営元に紐づく駐輪場の市町村のみ表示
     *
     * @param int $managementId
     * @return \Illuminate\Support\Collection
     */
    private function getCitiesList(int $managementId)
    {
        try {
            return DB::table('park')
                ->join('city', 'park.city_id', '=', 'city.city_id')
                ->where('park.management_id', $managementId)
                ->select('city.city_id', 'city.city_name')
                ->distinct()
                ->get();
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 市町村一覧取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return collect();
        }
    }

    /**
     * 駅名一覧取得（運営元フィルタ適用）
     * 
     * マルチテナント対応のため、運営元に紐づく駐輪場の駅のみ表示する。
     * 
     * @param int $managementId
     * @return \Illuminate\Support\Collection
     */
    private function getStationsList(int $managementId)
    {
        try {
            return DB::table('station')
                ->join('park', 'station.park_id', '=', 'park.park_id')
                ->where('park.management_id', $managementId)
                ->select('station.station_neighbor_station')
                ->distinct()
                ->get();
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駅名一覧取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return collect();
        }
    }

    /**
     * 駐輪場名一覧取得（運営元フィルタ適用）
     * 
     * マルチテナント対応のため、運営元に紐づく駐輪場のみ表示する。
     * 
     * @param int $managementId
     * @return \Illuminate\Support\Collection
     */
    private function getParksList(int $managementId)
    {
        try {
            return DB::table('park')
                ->where('management_id', $managementId)
                ->select('park_id', 'park_name')
                ->distinct()
                ->get();
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場名一覧取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return collect();
        }
    }

    /**
     * 駐輪場テーブルデータ取得（検索・ページング適用、運営元フィルタ適用）
     * 
     * マルチテナント対応のため、運営元に紐づく駐輪場のみ表示する。
     * 
     * @param int $managementId
     * @param int|null $cityId
     * @param string|null $stationName
     * @param int|null $parkId
     * @param int $page
     * @param int $perPage
     * @return array ['data' => Collection, 'total' => int]
     */
    private function getParksTableData(int $managementId, $cityId, $stationName, $parkId, int $page, int $perPage)
    {
        try {
            $query = DB::table('park')
                ->join('city', 'park.city_id', '=', 'city.city_id')
                ->leftJoin('station', 'park.park_id', '=', 'station.park_id')
                ->where('park.management_id', $managementId)
                ->select(
                    'park.park_id',
                    'park.park_name',
                    'park.park_ruby',
                    'city.city_name',
                    'city.city_id',
                    'station.station_neighbor_station',
                    'station.station_name_ruby'
                );

            // 検索条件適用
            if ($cityId) {
                $query->where('city.city_id', $cityId);
            }
            if ($stationName) {
                $query->where('station.station_neighbor_station', $stationName);
            }
            if ($parkId) {
                $query->where('park.park_id', $parkId);
            }

            $query->orderBy('park.park_id', 'asc');
            $total = $query->count();

            // ページング適用
            $data = $query
                ->skip(($page - 1) * $perPage)
                ->take($perPage)
                ->get();

            \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 駐輪場データ取得成功 management_id=" . $managementId . ", 件数=" . $total . ", page=" . $page);

            return [
                'data' => $data,
                'total' => $total,
            ];
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場テーブルデータ取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return [
                'data' => collect(),
                'total' => 0,
            ];
        }
    }

    /**
     * ゾーンデータを park_id でグループ化して取得（運営元フィルタ適用）
     * 
     * マルチテナント対応のため、運営元に紐づく駐輪場のゾーンのみ取得する。
     * 
     * @param int $managementId
     * @return \Illuminate\Support\Collection
     */
    private function getZonesByParkId(int $managementId)
    {
        try {
            return DB::table('zone')
                ->join('park', 'zone.park_id', '=', 'park.park_id')
                ->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
                ->where('park.management_id', $managementId)
                ->select(
                    'zone.zone_id',
                    'zone.park_id',
                    'zone.ptype_id',
                    'zone.psection_id',
                    'zone.zone_number',
                    'zone.zone_tolerance',
                    'psection.psection_subject'
                )
                ->get()
                ->groupBy('park_id');
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " zone データ取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return collect();
        }
    }

    /**
     * 予約データを park_id でグループ化して取得（運営元フィルタ適用）
     * 
     * マルチテナント対応のため、運営元に紐づく駐輪場の予約のみ取得する。
     * 
     * @param int $managementId
     * @return \Illuminate\Support\Collection
     */
    private function getReserveByParkId(int $managementId)
    {
        try {
            return DB::table('reserve')
                ->join('park', 'reserve.park_id', '=', 'park.park_id')
                ->where('park.management_id', $managementId)
                ->where('reserve.valid_flag', 1)
                ->select('reserve.reserve_id', 'reserve.park_id', 'reserve.ptype_id', 'reserve.psection_id')
                ->get()
                ->groupBy('park_id');
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " reserve データ取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return collect();
        }
    }

    /**
     * 駐輪場ごとの更新可能期間を取得（運営元フィルタ適用）
     * 
     * 
     * @param int $managementId
     * @return \Illuminate\Support\Collection
     */
    private function getParkGracePeriods(int $managementId)
    {
        try {
            return DB::table('park')
                ->where('management_id', $managementId)
                ->select(
                    'park_id',
                    'update_grace_period_start_date',
                    'update_grace_period_start_time',
                    'update_grace_period_end_date',
                    'update_grace_period_end_time'
                )
                ->get()
                ->keyBy('park_id');
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場更新可能期間取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return collect();
        }
    }

    /**
     * 運営元が取り扱う車種一覧を取得
     * 
     * マルチテナント対応のため、運営元ごとに表示する車種を可変にする。
     * 
     * @param int $managementId
     * @return array
     */
    private function getAvailableVehicles(int $managementId)
    {
        try {
            return DB::table('zone')
                ->join('park', 'zone.park_id', '=', 'park.park_id')
                ->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
                ->where('park.management_id', $managementId)
                ->whereNotNull('psection.psection_subject')
                ->select('psection.psection_subject')
                ->distinct()
                ->orderByRaw("FIELD(psection.psection_subject, '自転車', '原付', '自動二輪', '自動車')")
                ->pluck('psection_subject')
                ->toArray();
        } catch (\Exception $e) {
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 取り扱い車種取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
            return [];
        }
    }

    /**
     * 駐輪場ごと・車種ごとの状態を計算
     * 
     * @param \Illuminate\Support\Collection $parks
     * @param \Illuminate\Support\Collection $zones
     * @param \Illuminate\Support\Collection $reserve
     * @param \Illuminate\Support\Collection $parkGracePeriods
     * @param array $availableVehicles
     * @return \Illuminate\Support\Collection
     */
    private function calculateVehicleStatus($parks, $zones, $reserve, $parkGracePeriods, $availableVehicles)
    {
        $now = \Carbon\Carbon::now();

        foreach ($parks as $park) {
            $park->vehicle_status = [];

            foreach ($availableVehicles as $vehicle) {
                $zonesForType = ($zones[$park->park_id] ?? collect())->where('psection_subject', $vehicle);

                // 空き台数計算
                $hasVacancy = false;
                foreach ($zonesForType as $zone) {
                    $reserveCount = ($reserve[$park->park_id] ?? collect())
                        ->where('psection_id', $zone->psection_id)
                        ->where('ptype_id', $zone->ptype_id)
                        ->count();
                    $vacancy = $zone->zone_tolerance - $zone->zone_number - $reserveCount;
                    if ($vacancy > 0) {
                        $hasVacancy = true;
                        break;
                    }
                }

                // 猶予期間判定
                $grace = $parkGracePeriods[$park->park_id] ?? null;
                $inGrace = $this->isInGracePeriod($grace, $now);

                // 状態判定
                if ($zonesForType->isEmpty() || !$grace) {
                    $park->vehicle_status[$vehicle] = 'none';
                } elseif ($inGrace && $hasVacancy) {
                    $park->vehicle_status[$vehicle] = 'available';
                } elseif (!$inGrace) {
                    $park->vehicle_status[$vehicle] = 'out_of_period';
                } elseif (!$hasVacancy) {
                    $park->vehicle_status[$vehicle] = 'waiting';
                } else {
                    $park->vehicle_status[$vehicle] = 'none';
                }
            }
        }

        return $parks;
    }

    /**
     * 猶予期間内かどうかを判定
     * 
     * @param object|null $grace
     * @param \Carbon\Carbon $now
     * @return bool
     */
    private function isInGracePeriod($grace, $now)
    {
        if (!$grace) {
            return false;
        }

        // バリデーション
        if (
            !is_numeric($grace->update_grace_period_start_date) ||
            !preg_match('/^\d{1,2}:\d{2}$/', $grace->update_grace_period_start_time) ||
            !is_numeric($grace->update_grace_period_end_date) ||
            !preg_match('/^\d{1,2}:\d{2}$/', $grace->update_grace_period_end_time)
        ) {
            return false;
        }

        $year = $now->year;
        $month = $now->month;
        $startDay = (int)$grace->update_grace_period_start_date;
        $endDay = (int)$grace->update_grace_period_end_date;

        if ($startDay > $endDay) {
            // 月またぎ（例: 25日～5日）
            $prevMonth = $now->copy()->subMonth();
            $startPrev = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $prevMonth->year, $prevMonth->month, $startDay, $grace->update_grace_period_start_time));
            $endCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));

            $startCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
            $nextMonth = $month == 12 ? 1 : $month + 1;
            $nextYear = $month == 12 ? $year + 1 : $year;
            $endNext = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $nextYear, $nextMonth, $endDay, $grace->update_grace_period_end_time));

            return $now->between($startPrev, $endCurr) || $now->between($startCurr, $endNext);
        } else {
            // 同月（例: 5日～25日）
            $start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
            $end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));

            return $now->between($start, $end);
        }
    }

    public function regulationCheck(Request $request)
    {
        // GETパラメータを取得
        $parkId = $request->query('park_id');
        $psectionId = $request->query('psection_id');
        $ptypeId = $request->query('ptype_id');

        // 必要なDB処理やロジック
        $park_regulation = DB::table('park')->where('park_id', $parkId)->value('parking_regulations_flag');

        if ($park_regulation == 1) {
            // 駐輪規定画面へ
            return redirect()->route('regular_contract.regulation', [
                'park_id' => $parkId,
                'psection_id' => $psectionId,
                'ptype_id' => $ptypeId,
            ]);
        } else {
            // 契約情報入力画面へ
            return redirect()->route('regular_contract.input', [
                'park_id' => $parkId,
                'psection_id' => $psectionId,
                'ptype_id' => $ptypeId,
            ]);
        }
    }

    public function showRegulation(Request $request)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }
        $user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');

        // 必要なパラメータ取得
        $parkId = $request->query('park_id');
        $psectionId = $request->query('psection_id');
        $ptypeId = $request->query('ptype_id');

        $park_name = DB::table('park')->where('park_id', $parkId)->value('park_name');
        $psection_subject = DB::table('psection')->where('psection_id', $psectionId)->value('psection_subject');
        $ptype_subject = DB::table('ptype')->where('ptype_id', $ptypeId)->value('ptype_subject');
        $regulations_text = DB::table('parking_regulations')
            ->where('park_id', $parkId)
            ->where('psection_id', $psectionId)
            ->where('ptype_id', $ptypeId)
            ->value('regulations_text');

        \Log::info('駐輪規定確認画面にアクセス', [
            'user_id' => $user_id,
        ]);

        return view('regular_contract.regulation', [
            'park_id' => $parkId,
            'park_name' => $park_name,
            'psection_id' => $psectionId,
            'psection_subject' => $psection_subject,
            'ptype_id' => $ptypeId,
            'ptype_subject' => $ptype_subject,
            'regulations_text' => $regulations_text,
            'active_menu' => 'SWC-8-1', // この画面のID
            'user_name' => $user_name, // ユーザー名（ヘッダー用）
        ]);
    }

    public function insertRegulation(Request $request)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }
        $park_id = $request->input('park_id');
        $psection_id = $request->input('psection_id');
        $ptype_id = $request->input('ptype_id');

        DB::table('parking_regulations_read')->insert([
            'park_id' => $park_id,
            'psection_id' => $psection_id,
            'ptype_id' => $ptype_id,
            'user_id' => $user_id,
            'created_at' => now(),
        ]);

        // 契約入力画面へリダイレクト
        return redirect()->route('regular_contract.input', [
            'park_id' => $park_id,
            'psection_id' => $psection_id,
            'ptype_id' => $ptype_id,
        ]);
    }

    // 契約入力画面表示
    public function showContractForm(Request $request)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }
        $user = DB::table('user')->where('user_id', $user_id)->first();
        $park_id = $request->query('park_id');
        $park = DB::table('park')->where('park_id', $park_id)->first();
        $psection_id = $request->query('psection_id');
        $ptype_id = $request->query('ptype_id');
        $city_id = DB::table('park')->where('park_id', $park_id)->value('city_id');
        $terms_text = DB::table('terms')->where('city_id', $city_id)->value('terms_text');
        // 利用者区分をusertypeテーブルから取得
        $user_category = '';
        if (isset($user->user_categoryid)) {
            $usertype = DB::table('usertype')
                ->where('user_categoryid', $user->user_categoryid)
                ->first();
            if ($usertype && isset($usertype->usertype_subject1)) {
                $user_category = $usertype->usertype_subject1;
            }
        }
        $user->user_homephone = explode('-', $user->user_homephone ?? '');
        $user->user_mobile = explode('-', $user->user_mobile ?? '');
        $user->user_regident_zip_1 = substr($user->user_regident_zip ?? '', 0, 3);
        $user->user_regident_zip_2 = substr($user->user_regident_zip ?? '', 3, 4);
        $user->user_relate_zip_1 = substr($user->user_relate_zip ?? '', 0, 3);
        $user->user_relate_zip_2 = substr($user->user_relate_zip ?? '', 3, 4);

        \Log::info('新規定期契約-契約情報入力画面にアクセス', [
            'user_id' => $user_id,
        ]);

        session()->forget('show_terms_modal');

        return view('regular_contract.input', [
            'park' => $park,
            'psection_id' => $psection_id,
            'ptype_id' => $ptype_id,
            'terms_text' => $terms_text,
            'user' => $user,
            'user_name' => $user->user_name, // ユーザー名（ヘッダー用）
            'active_menu' => 'SWC-8-1', // この画面のID
            'user_category' => $user_category,
            'show_terms_modal' => true,
        ]);
    }
    public function inputCheck(Request $request)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }
        $user = DB::table('user')->where('user_id', $user_id)->first();

        $park_id = $request->input('park_id');
        $park = DB::table('park')->where('park_id', $park_id)->first();

        // バリデーションルール
        $rules = [
            'user_phonetic' => ['required', 'regex:/^[ァ-ヶー　\s]+$/u'],
            'user_regident_zip_1' => 'required|digits:3',
            'user_regident_zip_2' => 'required|digits:4',
            'user_regident_pre' => [
                'required',
                Rule::in([
                    '北海道',
                    '青森県',
                    '岩手県',
                    '宮城県',
                    '秋田県',
                    '山形県',
                    '福島県',
                    '茨城県',
                    '栃木県',
                    '群馬県',
                    '埼玉県',
                    '千葉県',
                    '東京都',
                    '神奈川県',
                    '新潟県',
                    '富山県',
                    '石川県',
                    '福井県',
                    '山梨県',
                    '長野県',
                    '岐阜県',
                    '静岡県',
                    '愛知県',
                    '三重県',
                    '滋賀県',
                    '京都府',
                    '大阪府',
                    '兵庫県',
                    '奈良県',
                    '和歌山県',
                    '鳥取県',
                    '島根県',
                    '岡山県',
                    '広島県',
                    '山口県',
                    '徳島県',
                    '香川県',
                    '愛媛県',
                    '高知県',
                    '福岡県',
                    '佐賀県',
                    '長崎県',
                    '熊本県',
                    '大分県',
                    '宮崎県',
                    '鹿児島県',
                    '沖縄県'
                ]),
            ],
            'user_regident_city' => ['required', 'string', 'max:20', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
            'user_regident_add' => ['required', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
            'user_homephone.*' => 'nullable|digits_between:1,5',
            'user_mobile.*' => 'nullable|digits_between:1,5',
            'user_submail' => 'nullable|email|different:user_primemail|max:80',
            'user_category' => ['required', Rule::in(['一般', '学生'])],
            'contract_reduction' => ['required', Rule::in(['はい', 'いいえ'])],
            'user_relate_zip_1' => 'nullable|digits:3',
            'user_relate_zip_2' => 'nullable|digits:4',
            'user_relate_pre' => [
                'nullable',
                Rule::in([
                    '北海道',
                    '青森県',
                    '岩手県',
                    '宮城県',
                    '秋田県',
                    '山形県',
                    '福島県',
                    '茨城県',
                    '栃木県',
                    '群馬県',
                    '埼玉県',
                    '千葉県',
                    '東京都',
                    '神奈川県',
                    '新潟県',
                    '富山県',
                    '石川県',
                    '福井県',
                    '山梨県',
                    '長野県',
                    '岐阜県',
                    '静岡県',
                    '愛知県',
                    '三重県',
                    '滋賀県',
                    '京都府',
                    '大阪府',
                    '兵庫県',
                    '奈良県',
                    '和歌山県',
                    '鳥取県',
                    '島根県',
                    '岡山県',
                    '広島県',
                    '山口県',
                    '徳島県',
                    '香川県',
                    '愛媛県',
                    '高知県',
                    '福岡県',
                    '佐賀県',
                    '長崎県',
                    '熊本県',
                    '大分県',
                    '宮崎県',
                    '鹿児島県',
                    '沖縄県'
                ]),
            ],
            'user_relate_city' => ['nullable', 'string', 'max:20', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
            'user_relate_add' => ['nullable', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
        ];
        // 性別欄が表示されている場合のみ必須
        if ((int)$park->gender_display_flag === 1) {
            $rules['user_gender'] = ['required', Rule::in(['男性', '女性'])];
        }
        // 生年月日欄が表示されている場合のみ必須
        if ((int)$park->bd_display_flag === 1) {
            $rules['user_birthdate'] = ['required', 'date'];
        }
        // 防犯登録番号欄が表示されている場合のみ必須
        if ((int)$park->securityreg_display_flag === 1) {
            $rules['user_securitynum'] = ['required', 'max:50', 'regex:/^[a-zA-Z0-9]+$/'];
        }
        // 利用者区分ごとの追加バリデーション
        if ($request->input('user_category') === '学生') {
            $rules['user_school'] = ['required', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'];
            $rules['user_graduate'] = ['required', 'date'];
        } else {
            $rules['user_workplace'] = ['nullable', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'];
        }
        $messages = [
            'user_phonetic.required' => 'フリガナが入力されていません。',
            'user_phonetic.regex' => 'フリガナはカタカナでご入力ください。',
            'user_gender.required' => '性別が入力されていません。',
            'user_gender.in' => '性別は「男性」または「女性」を選択してください。',
            'user_regident_zip_1.required' => '居住所の郵便番号（前半3桁）が入力されていません。',
            'user_regident_zip_2.required' => '居住所の郵便番号（後半4桁）が入力されていません。',
            'user_regident_zip_1.digits' => '居住所の郵便番号（前半3桁）は3桁の数字で入力してください。',
            'user_regident_zip_2.digits' => '居住所の郵便番号（後半4桁）は4桁の数字で入力してください。',
            'user_regident_pre.required' => '居住所の都道府県が選択されていません。',
            'user_regident_pre.in' => '都道府県は選択肢から選んでください。',
            'user_regident_city.required' => '居住所の市区町村が入力されていません。',
            'user_regident_city.max' => '居住所の市区町村は20文字以内で入力してください。',
            'user_regident_city.regex' => '居住所の市区町村に絵文字などの特殊文字は使用できません。',
            'user_regident_add.required' => '居住所の住所が入力されていません。',
            'user_regident_add.max' => '居住所の住所は50文字以内で入力してください。',
            'user_regident_add.regex' => '居住所の住所に絵文字などの特殊文字は使用できません。',
            'user_birthdate.required' => '生年月日が入力されていません。',
            'user_birthdate.date' => '生年月日は正しい日付で入力してください。',
            'user_homephone.*.digits_between' => '自宅電話番号はそれぞれ1～5桁の数字で入力してください。',
            'user_mobile.*.digits_between' => '携帯電話番号はそれぞれ1～5桁の数字で入力してください。',
            'user_submail.email' => '予備メールアドレスは正しい形式で入力してください。',
            'user_submail.max' => '予備メールアドレスは80文字以内で入力してください。',
            'user_submail.different' => 'メールアドレスと予備メールアドレスに同じアドレスを入力できません。',
            'user_category.required' => '利用者区分は必須です。',
            'user_category.in' => '利用者区分の値が不正です。',
            'contract_reduction.required' => '減免が選択されていません。',
            'contract_reduction.in' => '減免の値が不正です。',
            'user_workplace.max' => '勤務先は50文字以内で入力してください。',
            'user_workplace.regex' => '勤務先に絵文字などの特殊文字は使用できません。',
            'user_school.required' => '学校名が入力されていません。',
            'user_school.max' => '学校名は50文字以内で入力してください。',
            'user_school.regex' => '学校名に絵文字などの特殊文字は使用できません。',
            'user_graduate.required' => '卒業年月日が入力されていません。',
            'user_graduate.date' => '卒業年月日は正しい日付で入力してください。',
            'user_relate_zip_1.digits' => '住所の郵便番号（前半3桁）は3桁の数字で入力してください。',
            'user_relate_zip_2.digits' => '住所の郵便番号（後半4桁）は4桁の数字で入力してください。',
            'user_relate_pre.in' => '住所の都道府県は選択肢から選んでください。',
            'user_relate_city.max' => '住所の市区町村は20文字以内で入力してください。',
            'user_relate_city.regex' => '住所の市区町村に絵文字などの特殊文字は使用できません。',
            'user_relate_add.max' => '住所は50文字以内で入力してください。',
            'user_relate_add.regex' => '住所に絵文字などの特殊文字は使用できません。',
            'user_securitynum.required' => '防犯登録番号が入力されていません。',
            'user_securitynum.max' => '防犯登録番号は50文字以内で入力してください。',
            'user_securitynum.regex' => '防犯登録番号は英数字のみで入力してください。',
        ];
        try {
            $validated = $request->validate($rules, $messages);
        } catch (ValidationException $e) {
            return Redirect()->back()
                ->withErrors($e->validator)
                ->withInput($request->except('_token') + ['show_terms_modal' => false]);
        }

        if (empty(implode('', $request->input('user_homephone', []))) && empty(implode('', $request->input('user_mobile', [])))) {
            return redirect()->back()
                ->withErrors(['user_homephone' => '自宅電話番号または携帯電話番号のいずれかは必須です'])
                ->withInput($request->except('_token') + ['show_terms_modal' => false]);
        }

        $city = DB::table('city')->where('city_id', $park->city_id)->first();
        $matched = (mb_strpos($request->user_regident_city, $city->city_name) !== false);
        if ($matched === true) {
            $ward_residents = 1;
            DB::table('user')
                ->where('user_id', $user->user_id)
                ->update(['ward_residents' => $ward_residents]);
        } else {
            $contract_allowable_city_name = DB::table('contract_allowable_city')->where('city_id', $city->city_id)->value('contract_allowable_city_name');
            $matched_allowable = (mb_strpos($request->user_regident_city, $contract_allowable_city_name) !== false);
            if ($matched_allowable) {
                $ward_residents = 0;
                DB::table('user')
                    ->where('user_id', $user->user_id)
                    ->update(['ward_residents' => $ward_residents]);
            } else {
                return redirect()->back()->withErrors(['契約対象地域にお住まいでないためお申込みできません'])->withInput()->with(['show_terms_modal' => false]);
            }
        }
        if ($ward_residents == 1) {
            $usertype_subject2 = '区民';
        } else {
            $usertype_subject2 = '区民外';
        }

        $user_categoryid = DB::table('usertype')
            ->where('usertype_subject1', $request->user_category)
            ->where('usertype_subject2', $usertype_subject2)
            ->value('user_categoryid');

        $updateData = [
            'user_categoryid' => $user_categoryid,
            'user_phonetic' => $request->user_phonetic,
            'user_mobile' => implode('-', $request->input('user_mobile', [])),
            'user_homephone' => implode('-', $request->input('user_homephone', [])),
            'user_submail' => $request->filled('user_submail') ? $request->user_submail : null,
            'user_regident_zip' => $request->user_regident_zip_1 . $request->user_regident_zip_2,
            'user_regident_pre' => $request->user_regident_pre,
            'user_regident_city' => $request->user_regident_city,
            'user_regident_add' => $request->user_regident_add,
            'user_relate_zip'  => ($request->filled('user_relate_zip_1') && $request->filled('user_relate_zip_2')) ? ($request->user_relate_zip_1 . $request->user_relate_zip_2) : null,
            'user_relate_pre'  => $request->filled('user_relate_pre')  ? $request->user_relate_pre  : null,
            'user_relate_city' => $request->filled('user_relate_city') ? $request->user_relate_city : null,
            'user_relate_add'  => $request->filled('user_relate_add')  ? $request->user_relate_add  : null,
            'ward_residents' => $ward_residents,
            'user_workplace' => $request->user_category === '一般' ? $request->user_workplace : null,
            'user_school'    => $request->user_category === '学生' ? $request->user_school : null,
            'user_graduate'  => $request->user_category === '学生' ? $request->user_graduate : null,
            'updated_at' => now()
        ];

        // 性別欄が表示されている場合のみ追加
        if (!empty($park->gender_display_flag) && $park->gender_display_flag == 1) {
            $updateData['user_gender'] = $request->user_gender;
        }

        // 生年月日欄が表示されている場合のみ追加
        if (!empty($park->bd_display_flag) && $park->bd_display_flag == 1) {
            $updateData['user_birthdate'] = $request->user_birthdate;
            $updateData['user_age'] = $request->user_age;
        }

        DB::table('user')
            ->where('user_id', $user->user_id)
            ->update($updateData);

        $zone_id = DB::table('zone')
            ->where('park_id', $request->park_id)
            ->where('ptype_id', $request->ptype_id)
            ->where('psection_id', $request->psection_id)
            ->orderBy('zone_sort', 'asc')
            ->value('zone_id');

        $contract_id = DB::table('regular_contract')->insertGetId([
            'created_at' => now(),
            'updated_at' => now(),
            'user_id' => $user->user_id,
            'user_categoryid' => $user_categoryid,
            'park_id' => $park->park_id,
            'contract_created_at' => now(),
            'contract_reduction' => $request->contract_reduction === 'はい' ? 1 : 0,
            'update_flag' => 2,
            'contract_cancel_flag' => 0,
            'psection_id' => $request->psection_id,
            'ptype_id' => $request->ptype_id,
            'zone_id' => $zone_id
        ]);

        $contractUpdateData = [
            'contract_qr_id' => DB::raw("TO_BASE64(AES_ENCRYPT($contract_id, 'LJLASR4FAS34SAADFA72ASDFALLSDRGT'))")
        ];
        // 防犯登録番号が表示されている場合のみ追加
        if (!empty($park->securityreg_display_flag) && $park->securityreg_display_flag == 1) {
            $contractUpdateData['user_securitynum'] = $request->user_securitynum;
        }

        DB::table('regular_contract')
            ->where('contract_id', $contract_id)
            ->update($contractUpdateData);

        return redirect()->route('regular_contract.upload_identity_create', [
            'contract_id' => $contract_id,
        ]);
    }

    public function showUploadIdentityCreate(Request $request)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }
        $user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
        $contract = DB::table('regular_contract')->where('contract_id', $request->contract_id)->first();

        \Log::info('新規定期契約-本人確認書類アップロード画面にアクセス', [
            'user_id' => $user_id,
        ]);

        return view('regular_contract.upload_identity_create', [
            'contract_id' => $request->contract_id,
            'park_id' => $contract->park_id,
            'psection_id' => $contract->psection_id,
            'ptype_id' => $contract->ptype_id,
            'user_name' => $user_name,
            'active_menu' => 'SWC-8-1'
        ]);
    }
    public function confirmUploadIdentity(Request $request, $contract_id)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }

        $validator = Validator::make($request->all(), [
            'idcard_type' => 'required',
            'user_idcard' => 'required|file|mimes:jpg,jpeg,png,pdf',
        ], [
            'idcard_type.required' => '本人確認書類の種類を選択してください。',
            'user_idcard.required' => '本人確認書類のおもて画像をアップロードしてください。',
            'user_idcard.file' => '本人確認書類のおもて画像はファイルで指定してください。',
            'user_idcard.mimes' => 'アップロードできるファイル形式はjpg、jpeg、png、pdfのみです。',
        ]);
        if ($validator->fails()) {
            return redirect()->route('regular_contract.upload_identity_create', [
                'contract_id' => $contract_id,
            ])
                ->withErrors($validator)
                ->withInput();
        }

        // おもて画像保存（Laravel Storageを使用）
        $front = $request->file('user_idcard');
        $filename_front = uniqid('photo1_') . '.' . $front->getClientOriginalExtension();
        $front->storeAs('photo', $filename_front, 'public');

        // userテーブルに保存（チェック済フラグはSHJ-1処理後に設定）
        $updateData = [
            'photo_filename1' => $filename_front,
            'user_idcard' => $request->idcard_type,
            'updated_at' => now(),
        ];

        // ウラ画像がある場合保存し更新項目に追加
        if ($request->hasFile('user_idcard2')) {
            $back = $request->file('user_idcard2');
            $filename_back = uniqid('photo2_') . '.' . $back->getClientOriginalExtension();
            $back->storeAs('photo', $filename_back, 'public');
            $updateData['photo_filename2'] = $filename_back;
        }
        DB::table('user')->where('user_id', $user_id)->update($updateData);

        // SHJ-1 本人確認自動処理を実行
        $user = DB::table('user')->where('user_id', $user_id)->first();
        $park = DB::table('park')->where('park_id', $request->park_id)->first();
        $psection = DB::table('psection')->where('psection_id', $request->psection_id)->first();
        $usertype = DB::table('usertype')->where('user_categoryid', $user->user_categoryid)->first();


        // user_idからuser_seqを取得してSHJ-1に渡す
        $user_seq = $user->user_seq;
        $park_id = $request->park_id;

        \Log::info('SHJ-1バッチ処理開始', [
            'user_id' => $user_id,
            'user_seq' => $user_seq,
            'park_id' => $park_id,
            'contract_id' => $contract_id
        ]);

        try {
            // SHJ-1 コマンドを同期実行
            $exitCode = Artisan::call('shj:one', [
                'user_id' => $user_seq,
                'park_id' => $park_id
            ]);

            \Log::info('SHJ-1バッチ処理完了', [
                'exit_code' => $exitCode,
                'user_seq' => $user_seq,
                'park_id' => $park_id
            ]);
        } catch (\Exception $e) {
            \Log::error('SHJ-1バッチ処理でエラー発生', [
                'error' => $e->getMessage(),
                'user_seq' => $user_seq,
                'park_id' => $park_id
            ]);
        }

        // 処理結果に基づいて遷移
        return view('regular_contract.create_confirm', [
            'contract_id' => $request->contract_id,
            'user' => $user,
            'park' => $park,
            'psection' => $psection,
            'usertype' => $usertype,
            'user_name' => $user->user_name,
            'active_menu' => 'SWC-8-1'
        ]);
    }

    public function createConfirmNext($contract_id)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }
        $user = DB::table('user')->where('user_id', $user_id)->first();

        // 本人確認自動処理結果を取得
        if ($user && $user->user_idcard_chk_flag == 2) {
            // 本人確認OKの場合は利用期間選択画面へ
            // 必要な各マスタ情報を取得
            $contract = DB::table('regular_contract')->where('contract_id', $contract_id)->first();
            $park = DB::table('park')->where('park_id', $contract->park_id)->first();
            $city = DB::table('city')->where('city_id', $park->city_id)->first();
            $regular_type = DB::table('regular_type')->where('city_id', $city->city_id)->first();
            $usertype = DB::table('usertype')->where('user_categoryid', $contract->user_categoryid)->first();

            // 2重化しているマスタのため現在のテーブル名を取得
            $master_setting = DB::table('setting')->value('web_master');
            $tableName = 'price' . $master_setting;

            // 利用者区分に応じた逆利用フラグを取得
            $inverse_use_flag_column = ($usertype->usertype_subject1 == '一般') ? 'inverse_use_flag1' : 'inverse_use_flag2';
            $inverse_use_flag = $park->$inverse_use_flag_column;

            if ($inverse_use_flag == 0) {
                // regident_cityまたはrelate_cityが一致するか
                $is_same = (
                    strpos($user->user_regident_city, $city->city_name) !== false ||
                    strpos($user->user_relate_city, $city->city_name) !== false
                );
            } else {
                // regident_cityのみ一致するか
                $is_same = (strpos($user->user_regident_city, $city->city_name) !== false);
            }

            $target_subject2 = $is_same ? '区民' : '区民外';
            $user_categoryid = DB::table('usertype')
                ->where('usertype_subject1', $usertype->usertype_subject1)
                ->where('usertype_subject2', $target_subject2)
                ->where('usertype_subject3', $usertype->usertype_subject3)
                ->value('user_categoryid');

            // 駐輪場所マスタから料金を取得
            $prices = DB::table($tableName)
                ->where('park_id', $contract->park_id)
                ->where('psection_id', $contract->psection_id)
                ->where('ptype_id', $contract->ptype_id)
                ->where('user_categoryid', $user_categoryid)
                ->get();

            \Log::info('利用期間選択画面にアクセス', [
                'user_id' => $user_id,
            ]);

            // 利用期間選択画面へ遷移
            return view('regular_contract.create_select_period', [
                'active_menu' => 'SWC-8-1', // マイページメニューの選択状態用
                'user_name' => $user->user_name, // ユーザー名（ヘッダー用）
                'contract_id' => $contract_id,
                'regular_type' => $regular_type,
                'prices' => $prices,
            ]);
        } else {
            // NGの場合は本人確認書類確認中画面へ
            \Log::info('本人確認書類確認中画面にアクセス', [
                'user_id' => $user_id,
            ]);
            return view('regular_contract.create_idcard_checking', [
                'active_menu' => 'SWC-8-1', // マイページメニューの選択状態用
                'user_name' => $user->user_name, // ユーザー名（ヘッダー用）
            ]);
        }
    }

    public function selectPeriod(Request $request)
    {
        $user_id = session('user_id');
        if (!$user_id) {
            return redirect('/login');
        }

        $contract_id = $request->input('contract_id');

        $validator = Validator::make($request->all(), [
            'month' => 'required',
        ], [
            'month.required' => '契約期間が選択されていません。',
        ]);

        if ($validator->fails()) {
            return redirect()->route('regular_contract.create_confirm_error', ['contract_id' => $contract_id])
                ->withErrors($validator)
                ->withInput();
        }

        $month = $request->input('month');
        $price = $request->input('price_' . $month);

        $today = now();
        $day = $today->day;
        if ($day <= 19) {
            // 今月の1日
            $contract_periods = $today->copy()->startOfMonth()->format('Y-m-d');
        } else {
            // 翌月の1日
            $contract_periods = $today->copy()->addMonth()->startOfMonth()->format('Y-m-d');
        }
        $contract_periode = Carbon::parse($contract_periods)->addMonths($month - 1)->endOfMonth()->format('Y-m-d');
        // 契約更新
        DB::table('regular_contract')->where('contract_id', $contract_id)->update([
            'enable_months' => $month,
            'billing_amount' => $price,
            'contract_periods' => $contract_periods,
            'contract_periode' => $contract_periode,
            'updated_at' => now(),
        ]);

        // 完了後はウェルネット決済画面（仮）へリダイレクト
        return redirect()->route('wellnet.payment');
    }
}
