<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Support\Facades\Schema;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use App\Models\Park;
use App\Models\PriceA;
use App\Models\PriceB;
use Illuminate\Support\Facades\Auth;

class ReservesController
{
    /**
     * 予約一覧
     * - 基本表: reserve（r）
     * - 付加情報: user（u）, park（p）
     * - 画面変数: $list, $sort, $sort_type（利用者マスタの書式に準拠）
     *
     * reserve テーブルの主な列:
     *  reserve_id, contract_id, user_id, park_id, price_parkplaceid, psection_id,
     *  reserve_date, reserve_start, reserve_end, reserve_cancelday, valid_flag, ope_id など
     *  （DDL は dump の通り）【turn12file6†L15-L37】
     */
    public function list(Request $request)
    {
        // ── 並び順（既定: reserve_id DESC）──────────────────────────────
        $sort = $request->input('sort', 'reserve_id');
        $sortType = strtolower($request->input('sort_type', 'asc')) === 'desc' ? 'desc' : 'asc';

        // ── 絞り込み（必要最低限：利用者／駐輪場／期間）──────────────────
        $userId = trim((string) $request->input('user_id', ''));
        $parkId = trim((string) $request->input('park_id', ''));
        $fromDt = $request->input('reserve_date_from', '');
        $toDt = $request->input('reserve_date_to', '');
        $keyword = trim((string) $request->input('keyword', '')); // 利用者名かな など
        $validFlag = trim((string) $request->input('valid_flag', ''));
        $mailSentFrom = $request->input('mail_sent_from', '');
        $mailSentTo = $request->input('mail_sent_to', '');

        $priceUnion = DB::query()->fromSub(function ($sub) {
            $sub->from('price_a')
                ->select('price_parkplaceid', 'prine_name')
                ->unionAll(
                    DB::table('price_b')->select('price_parkplaceid', 'prine_name')
                );
        }, 'price_union');

        // ── クエリ構築 ────────────────────────────────────────────────
        $q = DB::table('reserve as r')
            ->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
            ->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
            ->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id')
            ->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id')
            ->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid')
            ->leftJoinSub($priceUnion, 'price_union', function ($join) {
                $join->on('price_union.price_parkplaceid', '=', 'r.price_parkplaceid');
            })
            ->select([
                'r.reserve_id',
                'r.contract_id',
                'r.contract_created_at',
                'r.user_id',
                'r.park_id',
                'r.price_parkplaceid',
                'r.psection_id',
                'r.reserve_date',
                'r.reserve_start',
                'r.reserve_end',
                'r.reserve_reduction',
                'r.reserve_auto_remind',
                'r.reserve_manual_remind',
                DB::raw('r.`800m_flag` as flag_800m'),
                'r.reserve_cancelday',
                'r.valid_flag',
                'r.reserve_manual',
                'r.reserve_notice',
                'r.sent_date',
                'r.reserve_order',
                'r.valid_flag',
                'r.ope_id',
                'r.user_categoryid',
                DB::raw('u.user_name as user_name'),
                DB::raw('u.user_phonetic as user_phonetic'),
                DB::raw('u.user_mobile as user_mobile'),
                DB::raw('p.park_name as park_name'),
                DB::raw('pt.ptype_subject as ptype_subject'),
                DB::raw('ps.psection_subject as psection_subject'),
                DB::raw('price_union.price_parkplaceid as display_price_parkplaceid'),
                DB::raw('price_union.prine_name as display_prine_name'),
                DB::raw('t.usertype_subject1 as usertype_subject1'),
                DB::raw('t.usertype_subject2 as usertype_subject2'),
                DB::raw('t.usertype_subject3 as usertype_subject3'),
            ]);

        if ($userId !== '')
            $q->where('r.user_id', 'like', "%{$userId}%");
        if ($parkId !== '')
            $q->where('r.park_id', '=', (int) $parkId);

        if ($fromDt)
            $q->whereDate('r.reserve_date', '>=', $fromDt);
        if ($toDt)
            $q->whereDate('r.reserve_date', '<=', $toDt);

        if ($keyword !== '') {
            $q->where(function ($w) use ($keyword) {
                $w->where('u.user_name', 'like', "%{$keyword}%")
                    ->orWhere('u.user_phonetic', 'like', "%{$keyword}%");
            });
        }
        if (in_array($validFlag, ['0', '1'], true)) {
            $q->where('r.valid_flag', '=', (int) $validFlag);
        }
        if ($mailSentFrom !== null && $mailSentFrom !== '') {
             $q->where('r.sent_date', '>=', $mailSentFrom);
         }
        if ($mailSentTo !== null && $mailSentTo !== '') {
             $q->where('r.sent_date', '<=', $mailSentTo);
         }

        // ソート許可カラム（JOIN 先も含む）
        $sortable = [
            'reserve_id',
            'contract_id',
            'contract_created_at',
            'user_categoryid',
            'user_id',
            'reserve_date',
            'park_price_name',
            'price_parkplaceid',
            'psection_subject',
            'ptype_subject',
            'park_name',
            'reserve_reduction',
            'reserve_auto_remind',
            'reserve_manual_remind',
            'flag_800m',
            'reserve_cancelday',
            'valid_flag',
            'sent_date',
            'reserve_manual',
            'reserve_notice',
            'reserve_order',
        ];
        if (!in_array($sort, $sortable, true)) {
            $sort = 'reserve_id';
        }

        $sortMap = [
            'reserve_id' => DB::raw('r.reserve_id'),
            'contract_id' => DB::raw('r.contract_id'),
            'contract_created_at' => DB::raw('r.contract_created_at'),
            'user_categoryid' => DB::raw('r.user_categoryid'),
            'user_id' => DB::raw('r.user_id'),
            'reserve_date' => DB::raw('r.reserve_date'),
            'park_price_name' => DB::raw('price_union.prine_name'),
            'price_parkplaceid' => DB::raw('r.price_parkplaceid'),
            'psection_subject' => DB::raw('ps.psection_subject'),
            'ptype_subject' => DB::raw('pt.ptype_subject'),
            'park_name' => DB::raw('p.park_name'),
            'reserve_reduction' => DB::raw('r.reserve_reduction'),
            'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'),
            'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'),
            'flag_800m' => DB::raw('r.`800m_flag`'),
            'reserve_cancelday' => DB::raw('r.reserve_cancelday'),
            'valid_flag' => DB::raw('r.valid_flag'),
            'sent_date' => DB::raw('r.sent_date'),
            'reserve_manual' => DB::raw('r.reserve_manual'),
            'reserve_notice' => DB::raw('r.reserve_notice'),
            'reserve_order' => DB::raw('r.reserve_order'),
        ];
        $sortColumn = $sortMap[$sort] ?? DB::raw('r.reserve_id');
        $q->orderBy($sortColumn, $sortType);

        $parkOptions = Park::query()
            ->orderBy('park_id', 'asc')
            ->pluck('park_name', 'park_id')
            ->toArray();

        $list = $q->paginate(50);

        $placeIds = $list->getCollection()
            ->pluck('price_parkplaceid')
            ->filter()
            ->unique()
            ->values()
            ->all();

        if (!empty($placeIds)) {
            $priceNamesA = PriceA::query()
                ->whereIn('price_parkplaceid', $placeIds)
                ->pluck('prine_name', 'price_parkplaceid')
                ->toArray();

            $priceNamesB = PriceB::query()
                ->whereIn('price_parkplaceid', $placeIds)
                ->pluck('prine_name', 'price_parkplaceid')
                ->toArray();

            // 駐輪場所名のマッピング（price_b で上書き）
            $priceNames = array_replace($priceNamesA, $priceNamesB);

            $list->setCollection(
                $list->getCollection()->map(function ($row) use ($priceNames) {
                    $id = $row->price_parkplaceid ?? null;
                    $row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames))
                        ? $priceNames[$id]
                        : null;
                    return $row;
                })
            );
        }

        return view('admin.reserves.list', [
            'list' => $list,
            'sort' => $sort,
            'sort_type' => $sortType,
            // 入力保持
            'user_id' => $userId,
            'park_id' => $parkId,
            'reserve_date_from' => $fromDt,
            'reserve_date_to' => $toDt,
            'keyword' => $keyword,
            'valid_flag' => $validFlag,
            'mail_sent_from' => $mailSentFrom,
            'mail_sent_to' => $mailSentTo,
            'parkOptions' => $parkOptions,
        ]);
    }

    /**
     * 予約追加（GET: 画面表示 / POST: 登録）
     */
    public function add(Request $request)
    {
        if ($request->isMethod('get')) {
            $userTypes = DB::table('usertype')
                ->orderBy('user_categoryid', 'asc')
                ->get([
                    'user_categoryid',
                    'usertype_subject1',
                    'usertype_subject2',
                    'usertype_subject3',
                ])
                ->map(function ($row) {
                    $labels = array_filter([
                        $row->usertype_subject1,
                        $row->usertype_subject2,
                        $row->usertype_subject3,
                    ], fn ($v) => $v !== null && $v !== '');
                    $row->display_name = $labels ? implode('/', $labels) : '';
                    return $row;
                });

            $parks = Park::query()
                ->orderBy('park_id', 'asc')
                ->get(['park_id', 'park_name']);

            $priceA = PriceA::query()
                ->select('price_parkplaceid', 'prine_name')
                ->get();
            $priceB = PriceB::query()
                ->select('price_parkplaceid', 'prine_name')
                ->get();
            $priceOptions = $priceA->merge($priceB)
                ->sortBy('price_parkplaceid', SORT_NATURAL)
                ->unique('price_parkplaceid')
                ->values();

            return view('admin.reserves.add', [
                'userTypes' => $userTypes,
                'parks' => $parks,
                'priceOptions' => $priceOptions,
            ]);
        }

        // 予約の最低限バリデーション（必要に応じて追加）
        $v = Validator::make($request->all(), [
            'user_id' => ['required', 'integer'],
            'park_id' => ['required', 'integer'],
            'reserve_date' => ['nullable', 'date'],
            'reserve_start' => ['nullable', 'date'],
            'reserve_end' => ['nullable', 'date'],
        ], [], [
            'user_id' => '利用者ID',
            'park_id' => '駐輪場ID',
        ]);

        if ($v->fails()) {
            return back()->withErrors($v)->withInput();
        }

        $now = now();
        $opeId = optional(Auth::user())->ope_id;

        $nextReserveId = DB::transaction(function () {
            $currentMax = DB::table('reserve')->max('reserve_id');
            return $currentMax ? $currentMax + 1 : 1;
        });

        DB::table('reserve')->insert([
            'reserve_id' => $nextReserveId,
            'user_id' => (int) $request->input('user_id'),
            'park_id' => (int) $request->input('park_id'),
            'contract_id' => $request->input('contract_id'),
            'price_parkplaceid' => $request->input('price_parkplaceid'),
            'psection_id' => $request->input('psection_id'),
            'reserve_date' => $request->input('reserve_date'),
            'reserve_start' => $now,
            'reserve_end' => $now,
            'valid_flag' => $request->input('valid_flag'),
            'ope_id' => $opeId,
            'created_at' => $now,
            'updated_at' => $now,
        ]);

        return redirect()->route('reserves')->with('success', '予約を登録しました。');
    }

    /**
     * 予約削除
     */
    public function delete(Request $request)
    {

        $normalizeIds = function ($raw) {

            if (is_string($raw)) {
                $raw = explode(',', $raw);
            }
            if (is_array($raw) && count($raw) === 1 && is_string($raw[0]) && str_contains($raw[0], ',')) {
                $raw = explode(',', $raw[0]);
            }
            $ids = array_map('intval', (array) $raw);
            $ids = array_values(array_unique(array_filter($ids, fn($v) => $v > 0)));
            return $ids;
        };

        if ($request->isMethod('get')) {

            $ids = $normalizeIds($request->input('ids', []));

            $rows = [];
            if ($ids) {
                $rows = DB::table('reserve as r')
                    ->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
                    ->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
                    ->whereIn('r.reserve_id', $ids)
                    ->select('r.*', 'u.user_name', 'p.park_name')
                    ->get();
            }
            return view('admin.reserves.delete', compact('rows', 'ids'));
        }


        if ($request->post('confirmed')) {
            $ids = $normalizeIds($request->input('ids', []));
            if ($ids) {
                $deleted = DB::table('reserve')->whereIn('reserve_id', $ids)->delete();
                return redirect()->route('reserves')->with(
                    $deleted ? 'success' : 'warning',
                    $deleted ? "{$deleted} 件を削除しました。" : '対象が見つかりませんでした。'
                );
            }
        }

        return redirect()->route('reserves')->with('warning', '削除対象がありません。');
    }


    public function edit(Request $request, $reserve_id)
    {
        $id = (int) $reserve_id;

        // 取得レコード（無ければ404）
        $row = DB::table('reserve')->where('reserve_id', $id)->first();
        if (!$row) {
            abort(404);
        }

        // POST: 更新処理（※reserveテーブルに確実にある列だけ更新）
        if ($request->isMethod('post')) {
            $v = Validator::make($request->all(), [
                'user_id' => ['required', 'integer'],
                'park_id' => ['required', 'integer'],
                'reserve_date' => ['nullable', 'date'],
                'reserve_start' => ['nullable', 'date'],
                'reserve_end' => ['nullable', 'date'],
            ], [], [
                'user_id' => '利用者ID',
                'park_id' => '駐輪場ID',
            ]);

            if ($v->fails()) {
                return back()->withErrors($v)->withInput();
            }

            $data = [
                'contract_id' => $request->input('contract_id'),
                'user_id' => (int) $request->input('user_id'),
                'park_id' => (int) $request->input('park_id'),
                'price_parkplaceid' => $request->input('price_parkplaceid'),
                'psection_id' => $request->input('psection_id'),
                'reserve_date' => $request->input('reserve_date'),
                'reserve_start' => $request->input('reserve_start'),
                'reserve_end' => $request->input('reserve_end'),
                'valid_flag' => $request->input('valid_flag'),
                'ope_id' => $request->input('ope_id'),
                'updated_at' => now(),
            ];
            DB::table('reserve')->where('reserve_id', $id)->update($data);

            return redirect()->route('reserves')->with('success', '予約を更新しました。');
        }

        // GET: 編集画面表示用の各種プルダウン（存在するテーブルだけ読む）
        $userOptions = DB::table('user')
            ->orderBy('user_id', 'asc')
            ->limit(5000)
            ->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
            ->toArray();

        $parkOptions = DB::table('park')
            ->orderBy('park_id', 'asc')
            ->pluck('park_name', 'park_id')
            ->toArray();

        $userTypeOptions = Schema::hasTable('usertype')
            ? DB::table('usertype')->orderBy('user_categoryid')
                ->pluck('print_name', 'user_categoryid')->toArray()
            : [];

        $parkplaceOptions = Schema::hasTable('price_parkplace')
            ? DB::table('price_parkplace')->orderBy('price_parkplaceid')
                ->pluck('price_parkplaceid', 'price_parkplaceid')->toArray()
            : [];

        $psectionOptions = Schema::hasTable('psection')
            ? DB::table('psection')->orderBy('psection_id')
                ->pluck(
                    Schema::hasColumn('psection', 'psection_name') ? 'psection_name' : 'psection_id',
                    'psection_id'
                )->toArray()
            : [];

        $ptypeOptions = Schema::hasTable('ptype')
            ? DB::table('ptype')->orderBy('ptype_id')
                ->pluck(
                    Schema::hasColumn('ptype', 'ptype_name') ? 'ptype_name' : 'ptype_id',
                    'ptype_id'
                )->toArray()
            : [];


        return view('admin.reserves.edit', compact(
            'row',
            'userOptions',
            'parkOptions',
            'userTypeOptions',
            'parkplaceOptions',
            'psectionOptions',
            'ptypeOptions'
        ));
    }

}
