<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Ope;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\StreamedResponse;
use App\Models\Feature;
use App\Models\Permission;
use App\Models\OpePermission;

class OpeController extends Controller
{
    /**
     * 一覧
     */
    public function list(Request $request)
    {
        $inputs = [
            'isMethodPost' => $request->isMethod('post'),
            'sort'         => $request->input('sort', 'ope_id'),
            'sort_type'    => $request->input('sort_type', 'asc'),
            'isExport'     => false,
        ];

        // Blade 側は $list / $sort / $sort_type を参照
        $list      = Ope::search($inputs);
        $sort      = $inputs['sort'];
        $sort_type = $inputs['sort_type'];

        return view('admin.opes.list', compact('list', 'sort', 'sort_type'));
    }

    /**
     * 新規登録（GET 画面 / POST 保存）
     */
    public function add(Request $request)
    {
        // ※機能（画面）一覧を取得（プルダウン用）
        $features = Feature::query()
            ->orderBy('id')
            ->get(['id', 'name']);

        // ※操作権限一覧を取得（チェックボックス用）
        $permissions = Permission::query()
            ->orderBy('id')
            ->get(['id', 'code', 'name']);

        if ($request->isMethod('get')) {
            return view('admin.opes.add', [
                'isEdit' => false,
                'record' => new Ope(),

                'ope_id'    => null,
                'ope_name'  => '',
                'ope_type'  => '',
                'ope_mail'  => '',
                'ope_phone' => '',

                'ope_sendalart_que1' => 0, 'ope_sendalart_que2' => 0, 'ope_sendalart_que3' => 0,
                'ope_sendalart_que4' => 0, 'ope_sendalart_que5' => 0, 'ope_sendalart_que6' => 0,
                'ope_sendalart_que7' => 0, 'ope_sendalart_que8' => 0, 'ope_sendalart_que9' => 0,
                'ope_sendalart_que10' => 0, 'ope_sendalart_que11' => 0, 'ope_sendalart_que12' => 0,
                'ope_sendalart_que13' => 0,
                'ope_auth1' => '', 'ope_auth2' => '', 'ope_auth3' => '', 'ope_auth4' => '',
                'ope_quit_flag' => 0, 'ope_quitday' => '',

                // ▼追加：権限設定UI用
                'features' => $features,
                'permissions' => $permissions,
                'selectedFeatureId' => old('feature_id', null),
            ]);
        }

        // 入力値を一旦取得
        $data = $request->all();

        // --- バリデーション ---
        $rules = [
            'login_id'  => 'required|string|max:255|unique:ope,login_id',
            'ope_name'  => 'required|string|max:255',
            'ope_type'  => 'required|string|max:50',
            'ope_mail'  => [
                'required',
                function ($attribute, $value, $fail) {
                    // ; でも , でもOK、保存時は ; に統一
                    $emails = array_map('trim', explode(';', str_replace(',', ';', $value)));
                    foreach ($emails as $email) {
                        if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
                            $fail("無効なメールアドレス形式です: {$email}");
                        }
                    }
                }
            ],
            'ope_phone' => 'nullable|string|max:50',
            'password'  => 'required|string|min:8|confirmed',
        ];

        $request->validate($rules);

        // --- 保存用にメールを ; 区切りに統一 ---
        $emails = array_filter(array_map('trim', explode(';', str_replace(',', ';', $data['ope_mail']))));
        $data['ope_mail'] = implode(';', $emails);

        // 保存処理
        $ope = new Ope();
        $ope->fill($data);
        $ope->save();

        return redirect()->route('opes')->with('success', '登録しました。');
    }

    /**
     * 編集（GET 画面 / POST 更新）
     * ※権限（自治体×機能×操作）も同画面で設定する
     */
    public function edit($id, Request $request)
    {
        $ope = Ope::getByPk($id);
        if (!$ope) abort(404);

        // ※機能（画面）一覧を取得（プルダウン用）
        $features = Feature::query()
            ->orderBy('id')
            ->get(['id', 'name']);

        // ※操作権限一覧を取得（チェックボックス用）
        $permissions = Permission::query()
            ->orderBy('id')
            ->get(['id', 'code', 'name']);

        // ※自治体ID（opeに紐づく想定）
        $municipalityId = (int)($ope->municipality_id ?? 0);

        if ($request->isMethod('get')) {
            return view('admin.opes.edit', [
                'isEdit' => true,
                'record' => $ope,

                // ▼追加：権限設定UI用
                'features' => $features,
                'permissions' => $permissions,
                'selectedFeatureId' => old('feature_id', null),
            ]);
        }

        /**
         * ▼権限設定の保存（feature_id + permission_ids[]）
         * ※画面側の保存ボタンを「権限も同時保存」にする場合はここで処理する
         * ※もし「基本情報の更新」と「権限更新」をボタンで分けたい場合は、別アクションに分離推奨
         */
        if ($request->has('feature_id')) {
            $request->validate([
                'feature_id' => ['required', 'integer', 'exists:features,id'],
                'permission_ids' => ['nullable', 'array'],
                'permission_ids.*' => ['integer', 'exists:permissions,id'],
            ]);

            $featureId = (int)$request->input('feature_id');
            $permissionIds = array_map('intval', (array)$request->input('permission_ids', []));

            DB::transaction(function () use ($municipalityId, $featureId, $permissionIds) {
                // ※機能単位で置換（自治体単位）
                OpePermission::replaceByFeature($municipalityId, $featureId, $permissionIds);
            });
        }

        // 入力値を一旦取得
        $data = $request->all();

        // --- バリデーション ---
        $rules = [
            'login_id'  => "required|string|max:255|unique:ope,login_id,{$id},ope_id",
            'ope_name'  => 'required|string|max:255',
            'ope_type'  => 'required|string|max:50',
            'ope_phone' => 'nullable|string|max:50',
            'ope_mail'  => [
                'required',
                function ($attribute, $value, $fail) {
                    $emails = array_map('trim', explode(';', str_replace(',', ';', $value)));
                    foreach ($emails as $email) {
                        if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
                            $fail("無効なメールアドレス形式です: {$email}");
                        }
                    }
                }
            ],
            'password' => 'nullable|string|min:8|confirmed',
        ];

        $request->validate($rules);

        // --- 保存用にメールを ; 区切りに統一 ---
        if (!empty($data['ope_mail'])) {
            $emails = array_filter(array_map('trim', explode(';', str_replace(',', ';', $data['ope_mail']))));
            $data['ope_mail'] = implode(';', $emails);
        }

        // パスワード空なら更新しない
        if (empty($data['password'])) {
            unset($data['password']);
        }

        // 保存処理
        $ope->fill($data);
        $ope->save();

        return redirect()->route('opes')->with('success', '更新しました。');
    }

    /**
     * 権限回顧（AJAX）
     * /opes/{id}/permissions?feature_id=xx
     * ※ope_permissionが自治体単位のため、opeの自治体IDで取得する
     */
    public function getPermissionsByFeature(int $id, Request $request)
    {
        $ope = Ope::getByPk($id);
        if (!$ope) abort(404);

        $featureId = (int)$request->query('feature_id');
        if ($featureId <= 0) {
            return response()->json([]);
        }

        $municipalityId = (int)($ope->municipality_id ?? 0);

        $ids = OpePermission::query()
            ->where('municipality_id', $municipalityId)
            ->where('feature_id', $featureId)
            ->pluck('permission_id')
            ->values();

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

    /**
     * 削除（単体 or 複数）
     */
    public function delete(Request $request)
    {
        $ids = [];

        // 単体削除
        if ($request->filled('id')) {
            $ids[] = (int)$request->input('id');
        }

        // 複数削除
        if ($request->filled('ids')) {
            $ids = array_merge($ids, array_map('intval', (array)$request->input('ids')));
        }

        $ids = array_unique($ids);

        if (!$ids) {
            return back()->with('error', '削除対象が選択されていません。');
        }

        Ope::deleteByPk($ids);

        return redirect()->route('opes')->with('success', '削除しました。');
    }

    /**
     * CSVインポート
     */
    public function import(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'file' => 'required|file|mimes:csv,txt|max:20480',
        ]);
        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        $file = $request->file('file')->getRealPath();
        $handle = fopen($file, 'r');
        if (!$handle) return back()->with('error', 'CSVを読み取れません。');

        $header = fgetcsv($handle);
        $header = array_map(fn($h) => trim(ltrim($h ?? '', "\xEF\xBB\xBF")), $header);

        $fillable = (new Ope())->getFillable();
        $rows = [];

        while (($row = fgetcsv($handle)) !== false) {
            $assoc = [];
            foreach ($header as $i => $key) {
                if (in_array($key, $fillable, true)) {
                    $assoc[$key] = $row[$i] ?? null;
                }
            }
            if ($assoc) $rows[] = $assoc;
        }
        fclose($handle);

        DB::transaction(function () use ($rows) {
            foreach ($rows as $data) {
                Ope::create($data);
            }
        });

        return redirect()->route('opes')->with('success', count($rows) . '件をインポートしました。');
    }

    /**
     * CSVエクスポート
     */
    public function export(): StreamedResponse
    {
        $filename = 'ope_' . now()->format('Ymd_His') . '.csv';
        $fillable = (new Ope())->getFillable();

        $response = new StreamedResponse(function () use ($fillable) {
            $out = fopen('php://output', 'w');
            fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF)); // BOM
            fputcsv($out, $fillable);

            Ope::orderBy('ope_id')->chunk(500, function ($chunk) use ($out, $fillable) {
                foreach ($chunk as $row) {
                    $line = [];
                    foreach ($fillable as $f) {
                        $line[] = $row->$f ?? '';
                    }
                    fputcsv($out, $line);
                }
            });
            fclose($out);
        });

        $response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
        $response->headers->set('Content-Disposition', "attachment; filename={$filename}");

        return $response;
    }
}
