<?php

namespace App\Controllers\Admin;

use App\Controllers\BaseController;
use App\Models\MenuModel;
use App\Models\MenuTypeModel;
use Config\Roles;

class Menu extends BaseController
{
    private MenuModel $menuModel;
    private MenuTypeModel $typeModel;

    public function __construct()
    {
        $this->menuModel = model(MenuModel::class);
        $this->typeModel = model(MenuTypeModel::class);
    }

    /**
     * 메뉴 등록·수정·삭제·순서변경 후 항상 같은 메뉴 관리 화면(mt_idx 유지)으로 돌아간다.
     * redirect()->back() 은 목록의 새 탭(target="_blank") 링크 클릭으로 세션 직전 URL(_ci_previous_url)이
     * 메뉴 대상 페이지로 덮어써지면 그 페이지로 이탈하므로, 명시적으로 메뉴 화면 URL 을 사용한다.
     */
    private function menusRedirect(int $mtIdx): \CodeIgniter\HTTP\RedirectResponse
    {
        $url = base_url('admin/menus');
        if ($mtIdx > 0) {
            $url .= '?mt_idx=' . $mtIdx;
        }

        return redirect()->to($url);
    }

    /**
     * 메뉴 관리 화면 (목록 + 등록/수정 폼). 지자체별 메뉴만 조회·관리.
     */
    public function index()
    {
        if ($deny = $this->denyUnlessLevel4Plus()) {
            return $deny;
        }
        helper('admin');
        $lgIdx = admin_effective_lg_idx();
        if ($lgIdx === null) {
            return redirect()->to(base_url('admin/select-local-government'))
                ->with('error', '메뉴를 관리하려면 먼저 지자체를 선택하세요.');
        }
        $types = $this->typeModel->orderBy('mt_sort', 'ASC')->findAll();
        $requestedMtIdx = (int) ($this->request->getGet('mt_idx') ?? 0);
        $mtIdx = $this->resolveMtIdx($requestedMtIdx, $types);
        $effectiveMtIdx = $mtIdx;
        $debugMode = $this->request->getGet('debug') === '1';
        $fallbackApplied = false;
        $list = $effectiveMtIdx > 0 ? $this->menuModel->getAllByType($effectiveMtIdx, $lgIdx) : [];
        $currentType = $mtIdx > 0 ? $this->typeModel->find($mtIdx) : null;
        $currentTypeCode = (string) ($currentType->mt_code ?? '');

        // 현재 지자체에 메뉴가 없으면, mt_idx별로 기본 지자체(lg_idx=1)의 메뉴를 한 번 복사한다.
        if ($effectiveMtIdx > 0 && empty($list)) {
            $this->menuModel->copyDefaultsFromLg($effectiveMtIdx, 1, $lgIdx);
            $list = $this->menuModel->getAllByType($effectiveMtIdx, $lgIdx);
        }

        // 운영 DB 불일치 대응: site 타입인데 mt_idx 매핑이 어긋난 경우(예: menu_type=2, menu는 4 사용)
        if (empty($list) && $currentTypeCode === 'site' && $effectiveMtIdx !== 4) {
            $fallbackMtIdx = 4;
            $fallbackList = $this->menuModel->getAllByType($fallbackMtIdx, $lgIdx);
            if (empty($fallbackList)) {
                $this->menuModel->copyDefaultsFromLg($fallbackMtIdx, 1, $lgIdx);
                $fallbackList = $this->menuModel->getAllByType($fallbackMtIdx, $lgIdx);
            }
            if (! empty($fallbackList)) {
                $effectiveMtIdx = $fallbackMtIdx;
                $list = $fallbackList;
                $fallbackApplied = true;
            }
        }

        if ($effectiveMtIdx > 0 && $currentTypeCode === 'site') {
            $this->menuModel->pruneInventoryManagementMenus($effectiveMtIdx, $lgIdx);
            $list = $this->menuModel->getAllByType($effectiveMtIdx, $lgIdx);
        }

        // 트리 순서대로 상위 메뉴 바로 아래에 하위 메뉴가 오도록 평탄화
        if (! empty($list)) {
            $tree = build_menu_tree($list);
            $list = flatten_menu_tree($tree);
        }

        return view('admin/layout', [
            'title'   => '메뉴 관리',
            'content' => view('admin/menu/index', [
                'types'      => $types,
                'mtIdx'      => $mtIdx,
                'mtCode'     => $currentTypeCode,
                'list'       => $list,
                'levelNames' => config('Roles')->levelNames,
                'debug_mode' => $debugMode,
                'debug_info' => [
                    'lg_idx'           => $lgIdx,
                    'requested_mt_idx' => $requestedMtIdx,
                    'resolved_mt_idx'  => $mtIdx,
                    'effective_mt_idx' => $effectiveMtIdx,
                    'resolved_mt_code' => $currentTypeCode,
                    'list_count'       => count($list),
                    'fallback_applied' => $fallbackApplied ? 'Y' : 'N',
                ],
            ]),
        ]);
    }

    /**
     * 메뉴 목록 JSON (트리 정렬된 평면 배열). 현재 지자체만.
     */
    public function list()
    {
        if ($deny = $this->denyUnlessLevel4Plus(true)) {
            return $deny;
        }
        $lgIdx = admin_effective_lg_idx();
        if ($lgIdx === null) {
            return $this->response->setJSON(['status' => 0, 'msg' => '지자체를 선택하세요.']);
        }
        $types = $this->typeModel->orderBy('mt_sort', 'ASC')->findAll();
        $requestedMtIdx = (int) $this->request->getGet('mt_idx');
        $mtIdx = $this->resolveMtIdx($requestedMtIdx, $types);
        if ($mtIdx <= 0) {
            return $this->response->setJSON(['status' => 0, 'msg' => 'mt_idx required']);
        }
        $type = $this->typeModel->find($mtIdx);
        if ($type && (string) ($type->mt_code ?? '') === 'site') {
            $this->menuModel->pruneInventoryManagementMenus($mtIdx, $lgIdx);
        }
        $list = $this->menuModel->getAllByType($mtIdx, $lgIdx);
        return $this->response->setJSON(['status' => 1, 'data' => $list]);
    }

    /**
     * 메뉴 등록 (현재 지자체 소속으로 저장)
     */
    public function store()
    {
        if ($deny = $this->denyUnlessLevel4Plus()) {
            return $deny;
        }
        $lgIdx = admin_effective_lg_idx();
        if ($lgIdx === null) {
            return redirect()->to(base_url('admin/select-local-government'))
                ->with('error', '메뉴를 등록하려면 먼저 지자체를 선택하세요.');
        }
        $mtIdx  = (int) $this->request->getPost('mt_idx');
        $mmPidx = (int) $this->request->getPost('mm_pidx');
        $mmDep  = (int) $this->request->getPost('mm_dep');
        $mmName = trim((string) $this->request->getPost('mm_name'));
        if ($mtIdx <= 0) {
            return $this->menusRedirect($mtIdx)->with('error', '메뉴 종류를 선택하세요.');
        }
        if ($mmName === '') {
            return $this->menusRedirect($mtIdx)->with('error', '메뉴명을 입력하세요.');
        }
        $mmNum = $this->menuModel->getNextNum($mtIdx, $lgIdx, $mmPidx, $mmDep);
        $data = [
            'mt_idx'     => $mtIdx,
            'lg_idx'     => $lgIdx,
            'mm_name'    => $mmName,
            'mm_link'    => (string) $this->request->getPost('mm_link'),
            'mm_pidx'    => $mmPidx,
            'mm_dep'     => $mmDep,
            'mm_num'     => $mmNum,
            'mm_cnode'   => 0,
            'mm_level'   => $this->normalizeMmLevel($mtIdx),
            'mm_is_view' => $this->request->getPost('mm_is_view') ? 'Y' : 'N',
        ];
        $this->menuModel->insert($data);
        if ($mmPidx > 0) {
            $this->menuModel->updateCnode($mmPidx, 1);
        }
        $this->menuModel->pruneInventoryManagementMenus($mtIdx, $lgIdx);
        $this->menuModel->syncTypeToAllLgs($mtIdx, $lgIdx);
        return $this->menusRedirect($mtIdx)->with('success', '메뉴가 등록되었습니다.');
    }

    /**
     * 메뉴 수정 (현재 지자체 소속 메뉴만 허용)
     */
    public function update(int $id)
    {
        if ($deny = $this->denyUnlessLevel4Plus()) {
            return $deny;
        }
        $lgIdx = admin_effective_lg_idx();
        if ($lgIdx === null) {
            return redirect()->to(base_url('admin/select-local-government'))
                ->with('error', '지자체를 선택하세요.');
        }
        $row = $this->menuModel->find($id);
        if (! $row) {
            return $this->menusRedirect((int) $this->request->getPost('mt_idx'))
                ->with('error', '메뉴를 찾을 수 없습니다.');
        }
        if ((int) $row->lg_idx !== $lgIdx) {
            return $this->menusRedirect((int) $row->mt_idx)
                ->with('error', '해당 지자체의 메뉴만 수정할 수 있습니다.');
        }
        $data = [
            'mm_name'    => (string) $this->request->getPost('mm_name'),
            'mm_link'    => (string) $this->request->getPost('mm_link'),
            'mm_level'   => $this->normalizeMmLevel((int) $row->mt_idx),
            'mm_is_view' => $this->request->getPost('mm_is_view') ? 'Y' : 'N',
        ];
        $this->menuModel->update($id, $data);
        $this->menuModel->pruneInventoryManagementMenus((int) $row->mt_idx, $lgIdx);
        $this->menuModel->syncTypeToAllLgs((int) $row->mt_idx, $lgIdx);
        return $this->menusRedirect((int) $row->mt_idx)->with('success', '메뉴가 수정되었습니다.');
    }

    /**
     * 메뉴 삭제 (현재 지자체 소속만 허용, 하위 있으면 불가)
     */
    public function delete(int $id)
    {
        if ($deny = $this->denyUnlessLevel4Plus()) {
            return $deny;
        }
        $lgIdx = admin_effective_lg_idx();
        if ($lgIdx === null) {
            return redirect()->to(base_url('admin/select-local-government'))
                ->with('error', '지자체를 선택하세요.');
        }
        $row = $this->menuModel->find($id);
        if (! $row || (int) $row->lg_idx !== $lgIdx) {
            return $this->menusRedirect((int) $this->request->getPost('mt_idx'))
                ->with('error', '해당 지자체의 메뉴만 삭제할 수 있습니다.');
        }
        $result = $this->menuModel->deleteSafe($id);
        if ($result['ok']) {
            $this->menuModel->pruneInventoryManagementMenus((int) $row->mt_idx, $lgIdx);
            $this->menuModel->syncTypeToAllLgs((int) $row->mt_idx, $lgIdx);
            return $this->menusRedirect((int) $row->mt_idx)->with('success', '메뉴가 삭제되었습니다.');
        }
        return $this->menusRedirect((int) $row->mt_idx)->with('error', $result['msg']);
    }

    /**
     * 순서 변경 (mm_idx[] 순서대로 mm_num 부여). 현재 지자체 메뉴만.
     */
    public function move()
    {
        if ($deny = $this->denyUnlessLevel4Plus()) {
            return $deny;
        }
        $lgIdx = admin_effective_lg_idx();
        if ($lgIdx === null) {
            return redirect()->to(base_url('admin/select-local-government'))
                ->with('error', '지자체를 선택하세요.');
        }
        $postMtIdx = (int) $this->request->getPost('mt_idx');

        // 순서 + 상위(부모) 변경 구조가 함께 전달되면 우선 처리 (하위 메뉴의 상위 이동 지원)
        $treeJson  = (string) $this->request->getPost('menu_tree');
        $structure = $treeJson !== '' ? json_decode($treeJson, true) : null;

        if (is_array($structure) && $structure !== []) {
            $orderedIds = array_values(array_filter(array_map(
                static fn ($it): int => (int) ($it['idx'] ?? 0),
                $structure
            ), static fn (int $v): bool => $v > 0));
            if (empty($orderedIds)) {
                return $this->menusRedirect($postMtIdx)->with('error', '순서를 적용할 메뉴가 없습니다.');
            }
            $firstRow = $this->menuModel->find($orderedIds[0]);
            $this->menuModel->setStructure($structure, $lgIdx);
            if ($firstRow && (int) $firstRow->lg_idx === $lgIdx) {
                $this->menuModel->pruneInventoryManagementMenus((int) $firstRow->mt_idx, $lgIdx);
                $this->menuModel->syncTypeToAllLgs((int) $firstRow->mt_idx, $lgIdx);
            }
            $mtIdx = $firstRow ? (int) $firstRow->mt_idx : $postMtIdx;
            return $this->menusRedirect($mtIdx)->with('success', '순서가 적용되었습니다.');
        }

        $ids = $this->request->getPost('mm_idx');
        if (! is_array($ids) || empty($ids)) {
            return $this->menusRedirect($postMtIdx)->with('error', '순서를 적용할 메뉴가 없습니다.');
        }
        $firstId = (int) ($ids[0] ?? 0);
        $firstRow = $firstId > 0 ? $this->menuModel->find($firstId) : null;
        $this->menuModel->setOrder($ids, $lgIdx);
        if ($firstRow && (int) $firstRow->lg_idx === $lgIdx) {
            $this->menuModel->pruneInventoryManagementMenus((int) $firstRow->mt_idx, $lgIdx);
            $this->menuModel->syncTypeToAllLgs((int) $firstRow->mt_idx, $lgIdx);
        }
        $mtIdx = $firstRow ? (int) $firstRow->mt_idx : $postMtIdx;
        return $this->menusRedirect($mtIdx)->with('success', '순서가 적용되었습니다.');
    }

    /**
     * 노출 대상: 전체(mm_level_all)이면 빈 문자열, 아니면 선택한 레벨을 쉼표 구분 문자열로
     */
    private function normalizeMmLevel(int $mtIdx): string
    {
        // 관리자 메뉴(admin)는 시민/판매소 노출을 허용하지 않음 → 지자체관리자(3)로 고정
        $type = $this->typeModel->find($mtIdx);
        if ($type && (string) $type->mt_code === 'admin') {
            return (string) Roles::LEVEL_LOCAL_ADMIN;
        }
        if ($this->request->getPost('mm_level_all')) {
            return '';
        }
        $levels = $this->request->getPost('mm_level');
        if (! is_array($levels) || empty($levels)) {
            return '';
        }
        $levels = array_map('intval', $levels);
        // super/본부(4·5)는 mm_level 저장 대상 아님. 1,2,3은 그대로 저장
        $levels = array_filter($levels, static fn ($v) => $v > 0 && ! \Config\Roles::isSuperAdminEquivalent($v));

        return implode(',', array_values($levels));
    }

    /**
     * 요청된 mt_idx를 현재 DB 상태에 맞게 보정.
     * - 유효한 mt_idx면 그대로 사용
     * - 레거시 site 값(2) 요청 시 site 타입의 실제 mt_idx로 치환
     * - 그 외 미지정/잘못된 값은 site 우선, 없으면 첫 타입으로 보정
     *
     * @param array<int,object> $types
     */
    private function resolveMtIdx(int $requestedMtIdx, array $types): int
    {
        if (empty($types)) {
            return 0;
        }

        $validTypeIds = array_map(static fn ($t): int => (int) ($t->mt_idx ?? 0), $types);
        if ($requestedMtIdx > 0 && in_array($requestedMtIdx, $validTypeIds, true)) {
            return $requestedMtIdx;
        }

        $siteType = $this->typeModel->where('mt_code', 'site')->first();
        if ($siteType !== null) {
            // 과거 링크(/admin/menus?mt_idx=2) 호환
            if ($requestedMtIdx === 2 || $requestedMtIdx <= 0 || ! in_array($requestedMtIdx, $validTypeIds, true)) {
                return (int) $siteType->mt_idx;
            }
        }

        return (int) $types[0]->mt_idx;
    }

    /**
     * 메뉴 관리는 레벨4 이상(슈퍼/본부 관리자)만 허용.
     *
     * @return \CodeIgniter\HTTP\RedirectResponse|\CodeIgniter\HTTP\ResponseInterface|null
     */
    private function denyUnlessLevel4Plus(bool $json = false)
    {
        $level = (int) session()->get('mb_level');
        if (Roles::isSuperAdminEquivalent($level)) {
            return null;
        }

        if ($json) {
            return $this->response->setJSON([
                'status' => 0,
                'msg' => '메뉴 관리는 레벨4 이상만 접근할 수 있습니다.',
            ]);
        }

        return redirect()->to(base_url('admin'))
            ->with('error', '메뉴 관리는 레벨4 이상만 접근할 수 있습니다.');
    }
}
