<?php

declare(strict_types=1);

namespace App\Controllers;

use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\HTTP\RedirectResponse;
use App\Models\BagInventoryModel;
use App\Models\BagIssueModel;
use App\Models\BagOrderModel;
use App\Models\BagOrderItemModel;
use App\Models\BagPriceModel;
use App\Models\BagReceivingModel;
use App\Models\BagSaleModel;
use App\Models\CodeKindModel;
use App\Models\CodeDetailModel;
use App\Models\CompanyModel;
use App\Models\PackagingUnitModel;
use App\Models\SalesAgencyModel;
use App\Models\ShopOrderModel;
use App\Models\DesignatedShopModel;
use App\Models\LocalGovernmentModel;
use Config\Roles;

class Bag extends BaseController
{
    /**
     * 로그인 사용자의 지자체 PK 반환 (미로그인/미지정 시 null)
     */
    private function lgIdx(): ?int
    {
        helper('admin');
        return admin_effective_lg_idx();
    }

    private function render(string $title, string $viewFile, array $data = []): string
    {
        return view('bag/layout/main', [
            'title'   => $title,
            'content' => view($viewFile, $data),
        ]);
    }

    // ──────────────────────────────────────────────
    // 기본정보관리 (단가·포장 단위 진입 허브)
    // ──────────────────────────────────────────────
    public function basicInfo(): string
    {
        return $this->render('기본정보관리', 'bag/basic_info', []);
    }

    /** 봉투 단가 조회 (사이트) — 기간·봉투구분·봉투코드 필터, 적용기간 겹침, 페이징·인쇄 */
    public function prices(): string|RedirectResponse
    {
        helper('admin');
        if ($this->request->is('post')) {
            $post = $this->request->getPost();
            $pick = static function (array $src, string $key): ?string {
                if (! array_key_exists($key, $src)) {
                    return null;
                }
                $v = $src[$key];
                if ($v === null || is_array($v)) {
                    return null;
                }
                $s = trim((string) $v);

                return $s === '' ? null : $s;
            };
            session()->setFlashdata('bag_prices_filter', [
                'start_y'    => $pick($post, 'start_y'),
                'start_m'    => $pick($post, 'start_m'),
                'start_d'    => $pick($post, 'start_d'),
                'end_y'      => $pick($post, 'end_y'),
                'end_m'      => $pick($post, 'end_m'),
                'end_d'      => $pick($post, 'end_d'),
                'bag_kind_e' => $pick($post, 'bag_kind_e'),
                'bag_code'   => $pick($post, 'bag_code'),
            ]);

            return redirect()->to(site_url('bag/prices'));
        }

        $lgIdx     = $this->lgIdx();
        $bagPrices = [];

        $get   = $this->request->getGet();
        $flash = session()->getFlashdata('bag_prices_filter');

        $readSrc = static function (array $src, string $key): ?string {
            if (! array_key_exists($key, $src)) {
                return null;
            }
            $v = $src[$key];
            if ($v === null || is_array($v)) {
                return null;
            }
            $s = trim((string) $v);

            return $s === '' ? null : $s;
        };

        $filterKeys = [
            'start_y', 'start_m', 'start_d',
            'end_y', 'end_m', 'end_d',
            'bag_kind_e', 'bag_code',
            'start_date', 'end_date',
        ];
        $hasExplicitGetFilter = false;
        foreach ($filterKeys as $fk) {
            $v = $get[$fk] ?? null;
            if ($v !== null && ! is_array($v) && trim((string) $v) !== '') {
                $hasExplicitGetFilter = true;
                break;
            }
        }

        $src = [];
        if ($hasExplicitGetFilter) {
            $src = $get;
        } elseif (is_array($flash)) {
            $src = $flash;
        }

        $sy = $readSrc($src, 'start_y');
        $sm = $readSrc($src, 'start_m');
        $sd = $readSrc($src, 'start_d');
        $ey = $readSrc($src, 'end_y');
        $em = $readSrc($src, 'end_m');
        $ed = $readSrc($src, 'end_d');

        $startDate = null;
        if ($sy !== null && $sy !== '' && $sm !== null && $sm !== '' && $sd !== null && $sd !== '') {
            $startDate = parse_ymd_from_triple($sy, $sm, $sd);
        }
        if ($startDate === null) {
            $g = $readSrc($src, 'start_date');
            $startDate = ($g !== null && $g !== '') ? $g : null;
        }

        $endDate = null;
        if ($ey !== null && $ey !== '' && $em !== null && $em !== '' && $ed !== null && $ed !== '') {
            $endDate = parse_ymd_from_triple($ey, $em, $ed);
        }
        if ($endDate === null) {
            $g = $readSrc($src, 'end_date');
            $endDate = ($g !== null && $g !== '') ? $g : null;
        }

        $startParts = ['y' => '', 'm' => '', 'd' => ''];
        $endParts   = ['y' => '', 'm' => '', 'd' => ''];
        if ($startDate !== null && preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $startDate, $m)) {
            $startParts = ['y' => $m[1], 'm' => (int) $m[2], 'd' => (int) $m[3]];
        } elseif ($sy !== null && $sm !== null && $sd !== null && $sy !== '' && $sm !== '' && $sd !== '') {
            $iy = (int) $sy;
            $im = (int) $sm;
            $id = (int) $sd;
            if ($iy >= 1000 && $iy <= 9999 && $im >= 1 && $im <= 12 && $id >= 1 && $id <= 31) {
                $startParts = ['y' => (string) $iy, 'm' => $im, 'd' => $id];
            }
        }
        if ($endDate !== null && preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $endDate, $m)) {
            $endParts = ['y' => $m[1], 'm' => (int) $m[2], 'd' => (int) $m[3]];
        } elseif ($ey !== null && $em !== null && $ed !== null && $ey !== '' && $em !== '' && $ed !== '') {
            $iy = (int) $ey;
            $im = (int) $em;
            $id = (int) $ed;
            if ($iy >= 1000 && $iy <= 9999 && $im >= 1 && $im <= 12 && $id >= 1 && $id <= 31) {
                $endParts = ['y' => (string) $iy, 'm' => $im, 'd' => $id];
            }
        }

        $dateYearMin = (int) date('Y') - 12;
        $dateYearMax = (int) date('Y') + 2;

        $bagKindE = $readSrc($src, 'bag_kind_e');
        $bagCode  = $readSrc($src, 'bag_code');
        $pager       = null;
        $bagCodes    = [];
        $bagKindOpts = [];
        $printLines  = [];
        $printLgName = '';

        if ($lgIdx !== null) {
            try {
                $priceModel = model(BagPriceModel::class);
                $builder    = $priceModel->where('bp_lg_idx', $lgIdx);

                if (($startDate !== null && $startDate !== '') || ($endDate !== null && $endDate !== '')) {
                    $qStart = ($startDate !== null && $startDate !== '') ? $startDate : $endDate;
                    $qEnd   = ($endDate !== null && $endDate !== '') ? $endDate : $startDate;
                    if (strcmp((string) $qStart, (string) $qEnd) > 0) {
                        [$qStart, $qEnd] = [$qEnd, $qStart];
                    }
                    $builder->where('bp_start_date <=', $qEnd);
                    $builder->groupStart()
                        ->where('bp_end_date IS NULL')
                        ->orWhere('bp_end_date >=', $qStart)
                    ->groupEnd();
                }

                if ($bagKindE !== null && $bagKindE !== '') {
                    $ek = model(CodeKindModel::class)->where('ck_code', 'E')->first();
                    if ($ek) {
                        $eDetail = model(CodeDetailModel::class)
                            ->where('cd_ck_idx', (int) $ek->ck_idx)
                            ->where('cd_code', $bagKindE)
                            ->where('cd_state', 1)
                            ->first();
                        if ($eDetail !== null) {
                            $builder->like('bp_bag_code', (string) $bagKindE, 'after');
                        }
                    }
                }

                if ($bagCode !== null && $bagCode !== '') {
                    $ok = model(CodeKindModel::class)->where('ck_code', 'O')->first();
                    if ($ok) {
                        $oDetail = model(CodeDetailModel::class)->findResolvedByKindAndCode((int) $ok->ck_idx, (string) $bagCode, $lgIdx);
                        if ($oDetail !== null) {
                            $builder->where('bp_bag_code', $bagCode);
                        }
                    }
                }

                $bagPrices = $builder->orderBy('bp_bag_code', 'ASC')->orderBy('bp_start_date', 'DESC')->paginate(20);

                $queryForPager = [];
                $tripleS         = $sy !== null && $sy !== '' && $sm !== null && $sm !== '' && $sd !== null && $sd !== '';
                $tripleE         = $ey !== null && $ey !== '' && $em !== null && $em !== '' && $ed !== null && $ed !== '';
                if ($tripleS) {
                    $queryForPager['start_y'] = $sy;
                    $queryForPager['start_m'] = $sm;
                    $queryForPager['start_d'] = $sd;
                } else {
                    $legacyS = $readSrc($src, 'start_date');
                    if ($legacyS !== null) {
                        $queryForPager['start_date'] = $legacyS;
                    }
                }
                if ($tripleE) {
                    $queryForPager['end_y'] = $ey;
                    $queryForPager['end_m'] = $em;
                    $queryForPager['end_d'] = $ed;
                } else {
                    $legacyE = $readSrc($src, 'end_date');
                    if ($legacyE !== null) {
                        $queryForPager['end_date'] = $legacyE;
                    }
                }
                if ($bagKindE !== null && $bagKindE !== '') {
                    $queryForPager['bag_kind_e'] = $bagKindE;
                }
                if ($bagCode !== null && $bagCode !== '') {
                    $queryForPager['bag_code'] = $bagCode;
                }
                $queryForPager = array_filter(
                    $queryForPager,
                    static fn ($v) => $v !== null && $v !== ''
                );
                $pagerPath = site_url('bag/prices');
                if ($queryForPager !== []) {
                    $pagerPath .= '?' . http_build_query($queryForPager);
                }
                $priceModel->pager->setPath($pagerPath);
                $pager = $priceModel->pager;

                $kindO = model(CodeKindModel::class)->where('ck_code', 'O')->first();
                $bagCodes = $kindO
                    ? model(CodeDetailModel::class)->getByKind((int) $kindO->ck_idx, true, $lgIdx)
                    : [];

                $kindE = model(CodeKindModel::class)->where('ck_code', 'E')->first();
                $bagKindOpts = $kindE
                    ? model(CodeDetailModel::class)->getByKind((int) $kindE->ck_idx, true, null)
                    : [];

                $lgRow = model(LocalGovernmentModel::class)->find($lgIdx);
                $printLgName = $lgRow !== null ? $lgRow->lg_name : '';
            } catch (DatabaseException $e) {
                log_message('error', '[prices] bag_price 조회 실패: ' . $e->getMessage());
            }
        }

        if (($startDate !== null && $startDate !== '') || ($endDate !== null && $endDate !== '')) {
            $qs = ($startDate !== null && $startDate !== '') ? $startDate : $endDate;
            $qe = ($endDate !== null && $endDate !== '') ? $endDate : $startDate;
            if (strcmp((string) $qs, (string) $qe) > 0) {
                [$qs, $qe] = [$qe, $qs];
            }
            $printLines[] = '조회기간(적용기간 겹침): ' . format_ymd_korean($qs) . ' ~ ' . format_ymd_korean($qe);
        }
        if ($bagKindE !== null && $bagKindE !== '') {
            foreach ($bagKindOpts as $cd) {
                if ((string) $cd->cd_code === (string) $bagKindE) {
                    $printLines[] = '봉투구분: ' . $cd->cd_name . ' (' . $bagKindE . ')';
                    break;
                }
            }
        }
        if ($bagCode !== null && $bagCode !== '') {
            $printLines[] = '봉투코드: ' . $bagCode;
        }

        $viewData = [
            'lgIdx'            => $lgIdx,
            'bagPrices'        => $bagPrices,
            'pager'            => $pager,
            'startDate'        => $startDate,
            'endDate'          => $endDate,
            'startParts'       => $startParts,
            'endParts'         => $endParts,
            'dateYearMin'      => $dateYearMin,
            'dateYearMax'      => $dateYearMax,
            'bag_kind_e'       => $bagKindE,
            'bag_code'         => $bagCode,
            'bag_codes'        => $bagCodes,
            'bag_kind_options' => $bagKindOpts,
            'printExtraLines'  => $printLines,
        ];
        if ($printLgName !== '') {
            $viewData['printLgName'] = $printLgName;
        }

        return $this->render('봉투 단가', 'bag/prices', $viewData);
    }

    /** 포장 단위 조회 (사이트) */
    public function packagingUnits(): string
    {
        $lgIdx           = $this->lgIdx();
        $packagingUnits = [];
        if ($lgIdx) {
            try {
                $packagingUnits = model(PackagingUnitModel::class)->where('pu_lg_idx', $lgIdx)->orderBy('pu_bag_code', 'ASC')->findAll();
            } catch (DatabaseException $e) {
                log_message('error', '[packagingUnits] packaging_unit 조회 실패: ' . $e->getMessage());
            }
        }

        return $this->render('포장 단위', 'bag/packaging_units', ['packagingUnits' => $packagingUnits]);
    }

    /**
     * 기본코드 종류·세부코드 조회 전용 (사이트 메뉴 기본코드관리)
     */
    public function codeKinds(): string
    {
        $kindModel   = model(CodeKindModel::class);
        $detailModel = model(CodeDetailModel::class);
        $kinds       = [];
        $countMap    = [];
        $lgIdx       = $this->lgIdx();
        try {
            $kinds = $kindModel->orderBy('ck_code', 'ASC')->findAll();
            foreach ($kinds as $row) {
                $countMap[$row->ck_idx] = (int) $detailModel->where('cd_ck_idx', $row->ck_idx)
                    ->filterByTenantScope($lgIdx)
                    ->countAllResults();
            }
        } catch (\Throwable $e) {
            log_message('error', '[codeKinds] 실패: {type} {message} @ {file}:{line} / lg={lg}, user={user}, level={level}', [
                'type'    => $e::class,
                'message' => $e->getMessage(),
                'file'    => $e->getFile(),
                'line'    => $e->getLine(),
                'lg'      => $lgIdx !== null ? (string) $lgIdx : 'null',
                'user'    => (string) (session()->get('mb_id') ?? ''),
                'level'   => (string) (session()->get('mb_level') ?? ''),
            ]);
            session()->setFlashdata('error', '기본코드 조회 중 오류가 발생했습니다. 관리자에게 로그 확인을 요청해 주세요.');
        }

        $level = (int) session()->get('mb_level');

        return $this->render('기본코드관리', 'bag/code_kinds', [
            'codeKinds'      => $kinds,
            'countMap'       => $countMap,
            'canManageKinds' => Roles::canManageCodeKindMaster($level),
        ]);
    }

    /**
     * 기본코드 세부 목록 (사이트 레이아웃). 등록·수정·삭제 폼은 /admin/code-details/* 유지.
     */
    public function codeDetails(int $ckIdx)
    {
        $kindModel   = model(CodeKindModel::class);
        $detailModel = model(CodeDetailModel::class);
        $kind        = null;
        try {
            $kind = $kindModel->find($ckIdx);
        } catch (\Throwable $e) {
            log_message('error', '[codeDetails] kind 조회 실패: {type} {message} @ {file}:{line} / ck={ck}, user={user}, level={level}', [
                'type'    => $e::class,
                'message' => $e->getMessage(),
                'file'    => $e->getFile(),
                'line'    => $e->getLine(),
                'ck'      => (string) $ckIdx,
                'user'    => (string) (session()->get('mb_id') ?? ''),
                'level'   => (string) (session()->get('mb_level') ?? ''),
            ]);
            return redirect()->to(site_url('bag/code-kinds'))->with('error', '세부코드 조회 중 오류가 발생했습니다. 관리자에게 로그 확인을 요청해 주세요.');
        }
        if ($kind === null) {
            return redirect()->to(site_url('bag/code-kinds'))->with('error', '코드 종류를 찾을 수 없습니다.');
        }

        $lgIdx = $this->lgIdx();
        try {
            $list  = $detailModel->where('cd_ck_idx', $ckIdx)
                ->filterByTenantScope($lgIdx)
                ->orderBy('cd_sort', 'ASC')
                ->orderBy('cd_idx', 'ASC')
                ->paginate(20);
            $pager = $detailModel->pager;
        } catch (\Throwable $e) {
            log_message('error', '[codeDetails] list 조회 실패: {type} {message} @ {file}:{line} / ck={ck}, lg={lg}, user={user}, level={level}', [
                'type'    => $e::class,
                'message' => $e->getMessage(),
                'file'    => $e->getFile(),
                'line'    => $e->getLine(),
                'ck'      => (string) $ckIdx,
                'lg'      => $lgIdx !== null ? (string) $lgIdx : 'null',
                'user'    => (string) (session()->get('mb_id') ?? ''),
                'level'   => (string) (session()->get('mb_level') ?? ''),
            ]);
            return redirect()->to(site_url('bag/code-kinds'))->with('error', '세부코드 조회 중 오류가 발생했습니다. 관리자에게 로그 확인을 요청해 주세요.');
        }

        helper('admin');
        $level      = (int) session()->get('mb_level');
        $adminLg    = admin_effective_lg_idx();
        $canManage  = Roles::canManageCodeMaster($level);
        $rowCanEdit = [];
        foreach ($list as $row) {
            $rowCanEdit[$row->cd_idx] = Roles::canEditCodeDetailRow($level, $row, $adminLg);
        }

        $title = ($canManage ? '세부코드 관리' : '세부코드 조회') . ' — ' . $kind->ck_name . ' (' . $kind->ck_code . ')';

        return $this->render($title, 'bag/code_details', [
            'kind'       => $kind,
            'list'       => $list,
            'pager'      => $pager,
            'canManage'  => $canManage,
            'rowCanEdit' => $rowCanEdit,
        ]);
    }

    // ──────────────────────────────────────────────
    // 발주 입고 관리
    // ──────────────────────────────────────────────
    public function purchaseInbound(): string
    {
        $lgIdx = $this->lgIdx();
        $data = ['orders' => [], 'receivings' => [], 'startDate' => null, 'endDate' => null];

        if ($lgIdx) {
            $startDate = $this->request->getGet('start_date');
            $endDate   = $this->request->getGet('end_date');
            $data['startDate'] = $startDate;
            $data['endDate']   = $endDate;

            // 발주 목록
            $orderBuilder = model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx);
            if ($startDate) $orderBuilder->where('bo_order_date >=', $startDate);
            if ($endDate)   $orderBuilder->where('bo_order_date <=', $endDate);
            $data['orders'] = $orderBuilder->orderBy('bo_order_date', 'DESC')->paginate(20, 'orders');
            $data['orderPager'] = model(BagOrderModel::class)->pager;

            // 발주별 품목 합계
            $itemSummary = [];
            foreach ($data['orders'] as $order) {
                $items = model(BagOrderItemModel::class)->where('boi_bo_idx', $order->bo_idx)->findAll();
                $totalQty = 0;
                $totalAmt = 0;
                foreach ($items as $it) {
                    $totalQty += (int) $it->boi_qty_sheet;
                    $totalAmt += (float) $it->boi_amount;
                }
                $itemSummary[$order->bo_idx] = ['qty' => $totalQty, 'amount' => $totalAmt, 'count' => count($items)];
            }
            $data['itemSummary'] = $itemSummary;

            // 입고 목록
            $recvBuilder = model(BagReceivingModel::class)->where('br_lg_idx', $lgIdx);
            if ($startDate) $recvBuilder->where('br_receive_date >=', $startDate);
            if ($endDate)   $recvBuilder->where('br_receive_date <=', $endDate);
            $data['receivings'] = $recvBuilder->orderBy('br_receive_date', 'DESC')->paginate(20, 'receivings');
            $data['recvPager'] = model(BagReceivingModel::class)->pager;
        }

        return $this->render('발주 입고 관리', 'bag/purchase_inbound', $data);
    }

    // ──────────────────────────────────────────────
    // 불출 관리
    // ──────────────────────────────────────────────
    public function issue(): string
    {
        $lgIdx = $this->lgIdx();
        $data = ['list' => [], 'startDate' => null, 'endDate' => null];

        if ($lgIdx) {
            $startDate = $this->request->getGet('start_date');
            $endDate   = $this->request->getGet('end_date');
            $data['startDate'] = $startDate;
            $data['endDate']   = $endDate;

            $builder = model(BagIssueModel::class)->where('bi2_lg_idx', $lgIdx);
            if ($startDate) $builder->where('bi2_issue_date >=', $startDate);
            if ($endDate)   $builder->where('bi2_issue_date <=', $endDate);
            $data['list'] = $builder->orderBy('bi2_issue_date', 'DESC')->paginate(20);
            $data['pager'] = model(BagIssueModel::class)->pager;
        }

        return $this->render('불출 관리', 'bag/issue', $data);
    }

    // ──────────────────────────────────────────────
    // 재고 관리
    // ──────────────────────────────────────────────
    public function inventory(): string
    {
        $lgIdx = $this->lgIdx();
        $data = ['list' => []];

        if ($lgIdx) {
            $invModel = model(BagInventoryModel::class);
            $data['list'] = $invModel->where('bi_lg_idx', $lgIdx)->orderBy('bi_bag_code', 'ASC')->paginate(20);
            $data['pager'] = $invModel->pager;
        }

        return $this->render('재고 관리', 'bag/inventory', $data);
    }

    // ──────────────────────────────────────────────
    // 판매 관리
    // ──────────────────────────────────────────────
    public function sales(): string
    {
        $lgIdx = $this->lgIdx();
        $data = ['salesList' => [], 'orderList' => [], 'startDate' => null, 'endDate' => null];

        if ($lgIdx) {
            $startDate = $this->request->getGet('start_date');
            $endDate   = $this->request->getGet('end_date');
            $data['startDate'] = $startDate;
            $data['endDate']   = $endDate;

            // 판매/반품
            $saleBuilder = model(BagSaleModel::class)->where('bs_lg_idx', $lgIdx);
            if ($startDate) $saleBuilder->where('bs_sale_date >=', $startDate);
            if ($endDate)   $saleBuilder->where('bs_sale_date <=', $endDate);
            $data['salesList'] = $saleBuilder->orderBy('bs_sale_date', 'DESC')->paginate(20, 'sales');
            $data['salesPager'] = model(BagSaleModel::class)->pager;

            // 주문 접수
            $orderBuilder = model(ShopOrderModel::class)->where('so_lg_idx', $lgIdx);
            if ($startDate) $orderBuilder->where('so_delivery_date >=', $startDate);
            if ($endDate)   $orderBuilder->where('so_delivery_date <=', $endDate);
            $data['orderList'] = $orderBuilder->orderBy('so_idx', 'DESC')->paginate(20, 'shoporders');
            $data['orderPager'] = model(ShopOrderModel::class)->pager;
        }

        return $this->render('판매 관리', 'bag/sales', $data);
    }

    // ──────────────────────────────────────────────
    // 판매 현황
    // ──────────────────────────────────────────────
    public function salesStats(): string
    {
        $lgIdx = $this->lgIdx();
        $data = ['result' => [], 'startDate' => null, 'endDate' => null];

        if ($lgIdx) {
            $startDate = $this->request->getGet('start_date');
            $endDate   = $this->request->getGet('end_date');
            $data['startDate'] = $startDate;
            $data['endDate']   = $endDate;

            $builder = model(BagSaleModel::class)->where('bs_lg_idx', $lgIdx)->where('bs_type', 'sale');
            if ($startDate) $builder->where('bs_sale_date >=', $startDate);
            if ($endDate)   $builder->where('bs_sale_date <=', $endDate);
            $data['result'] = $builder->orderBy('bs_sale_date', 'DESC')->paginate(20);
            $data['pager'] = model(BagSaleModel::class)->pager;
        }

        return $this->render('판매 현황', 'bag/sales_stats', $data);
    }

    // ──────────────────────────────────────────────
    // 봉투 수불 관리
    // ──────────────────────────────────────────────
    public function flow(): string
    {
        $lgIdx = $this->lgIdx();
        $data = ['receiving' => [], 'sales' => [], 'issues' => [], 'inventory' => [], 'startDate' => null, 'endDate' => null];

        if ($lgIdx) {
            $startDate = $this->request->getGet('start_date');
            $endDate   = $this->request->getGet('end_date');
            $data['startDate'] = $startDate;
            $data['endDate']   = $endDate;

            $data['inventory'] = model(BagInventoryModel::class)->where('bi_lg_idx', $lgIdx)->findAll();

            $recvBuilder = model(BagReceivingModel::class)->where('br_lg_idx', $lgIdx);
            if ($startDate) $recvBuilder->where('br_receive_date >=', $startDate);
            if ($endDate)   $recvBuilder->where('br_receive_date <=', $endDate);
            $data['receiving'] = $recvBuilder->findAll();

            $saleBuilder = model(BagSaleModel::class)->where('bs_lg_idx', $lgIdx);
            if ($startDate) $saleBuilder->where('bs_sale_date >=', $startDate);
            if ($endDate)   $saleBuilder->where('bs_sale_date <=', $endDate);
            $data['sales'] = $saleBuilder->findAll();

            $issueBuilder = model(BagIssueModel::class)->where('bi2_lg_idx', $lgIdx);
            if ($startDate) $issueBuilder->where('bi2_issue_date >=', $startDate);
            if ($endDate)   $issueBuilder->where('bi2_issue_date <=', $endDate);
            $data['issues'] = $issueBuilder->findAll();
        }

        return $this->render('봉투 수불 관리', 'bag/flow', $data);
    }

    // ──────────────────────────────────────────────
    // 통계 분석 관리
    // ──────────────────────────────────────────────
    public function analytics(): string
    {
        return $this->render('통계 분석 관리', 'bag/analytics', []);
    }

    // ──────────────────────────────────────────────
    // 창 (프로그램 창 관리 - 추후)
    // ──────────────────────────────────────────────
    public function window(): string
    {
        return $this->render('창', 'bag/window', []);
    }

    // ──────────────────────────────────────────────
    // 도움말
    // ──────────────────────────────────────────────
    public function help(): string
    {
        return $this->render('도움말', 'bag/help', []);
    }

    // ──────────────────────────────────────────────
    // 재고 조정 (실사)
    // ──────────────────────────────────────────────
    public function inventoryAdjust(): string
    {
        $lgIdx = $this->lgIdx();
        $inventory = $lgIdx ? model(BagInventoryModel::class)->where('bi_lg_idx', $lgIdx)->orderBy('bi_bag_code')->findAll() : [];
        return $this->render('재고 조정', 'bag/inventory_adjust', compact('inventory'));
    }

    public function inventoryAdjustStore()
    {
        helper('admin');
        $lgIdx = $this->lgIdx();
        if (! $lgIdx) {
            return redirect()->to(site_url('bag/inventory'))->with('error', '지자체를 선택해 주세요.');
        }

        $rules = [
            'bag_code'    => 'required|max_length[50]',
            'adjust_type' => 'required|in_list[set,add,sub]',
            'qty'         => 'required|is_natural',
        ];
        if (! $this->validate($rules)) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $bagCode = $this->request->getPost('bag_code');
        $type    = $this->request->getPost('adjust_type');
        $qty     = (int) $this->request->getPost('qty');

        $invModel = model(BagInventoryModel::class);
        $existing = $invModel->where('bi_lg_idx', $lgIdx)->where('bi_bag_code', $bagCode)->first();

        if ($type === 'set') {
            if ($existing) {
                $invModel->update($existing->bi_idx, ['bi_qty' => $qty, 'bi_updated_at' => date('Y-m-d H:i:s')]);
            }
        } elseif ($type === 'add') {
            $bagName = $existing ? $existing->bi_bag_name : '';
            $invModel->adjustQty($lgIdx, $bagCode, $bagName, $qty);
        } elseif ($type === 'sub') {
            $bagName = $existing ? $existing->bi_bag_name : '';
            $invModel->adjustQty($lgIdx, $bagCode, $bagName, -$qty);
        }

        return redirect()->to(site_url('bag/inventory'))->with('success', '재고가 조정되었습니다.');
    }

    // ══════════════════════════════════════════════
    //  CRUD — 사이트 레이아웃으로 등록/처리 폼 제공
    // ══════════════════════════════════════════════

    // --- 불출 등록 ---
    public function issueCreate(): string
    {
        $kind    = model(CodeKindModel::class)->where('ck_code', 'O')->first();
        $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $this->lgIdx()) : [];
        return $this->render('불출 처리', 'bag/create_bag_issue', compact('bagCodes'));
    }

    public function issueStore()
    {
        $admin = new \App\Controllers\Admin\BagIssue();
        $admin->initController($this->request, $this->response, service('logger'));
        $result = $admin->store();
        if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) {
            $to = (string) $result->getHeaderLine('Location');
            $to = str_replace('/admin/bag-issues', '/bag/issue', $to);
            return redirect()->to($to)->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors'));
        }
        return redirect()->to(site_url('bag/issue'))->with('success', '불출 처리되었습니다.');
    }

    public function issueCancel(int $id)
    {
        $admin = new \App\Controllers\Admin\BagIssue();
        $admin->initController($this->request, $this->response, service('logger'));
        $admin->cancel($id);
        return redirect()->to(site_url('bag/issue'))->with('success', session()->getFlashdata('success') ?? '취소되었습니다.');
    }

    // --- 발주 등록 ---
    public function orderCreate(): string
    {
        helper('admin');
        $lgIdx = $this->lgIdx();
        $companies = $lgIdx
            ? model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->whereIn('cp_type', ['제작업체', 'manufacturer'])->where('cp_state', 1)->findAll()
            : [];
        $agencies = $lgIdx ? model(SalesAgencyModel::class)->where('sa_lg_idx', $lgIdx)->orderForDisplay()->findAll() : [];
        $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
        $bagCodes = $kind ? model(CodeDetailModel::class)->where('cd_ck_idx', $kind->ck_idx)->where('cd_state', 1)->orderBy('cd_sort')->findAll() : [];
        return $this->render('발주 등록', 'bag/create_bag_order', compact('companies', 'agencies', 'bagCodes'));
    }

    public function orderStore()
    {
        $admin = new \App\Controllers\Admin\BagOrder();
        $admin->initController($this->request, $this->response, service('logger'));
        $result = $admin->store();
        if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) {
            return redirect()->to(site_url('bag/purchase-inbound'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors'));
        }
        return redirect()->to(site_url('bag/purchase-inbound'))->with('success', '발주 등록되었습니다.');
    }

    public function orderCancel(int $id)
    {
        helper('admin');
        $lgIdx = $this->lgIdx();
        if (!$lgIdx) {
            return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 확인할 수 없습니다.');
        }
        $orderModel = model(BagOrderModel::class);
        $order      = $orderModel->find($id);
        if (!$order || (int) $order->bo_lg_idx !== $lgIdx) {
            return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '발주를 찾을 수 없습니다.');
        }
        $before = (array) $order;
        $orderModel->update($id, ['bo_status' => 'cancelled', 'bo_moddate' => date('Y-m-d H:i:s')]);
        helper('audit');
        audit_log('update', 'bag_order', $id, $before, ['bo_status' => 'cancelled']);

        return redirect()->to(site_url('bag/purchase-inbound'))->with('success', '발주가 취소되었습니다.');
    }

    // --- 입고 처리 ---
    public function receivingCreate(): string
    {
        helper('admin');
        $lgIdx = $this->lgIdx();
        $orders = $lgIdx ? model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx)->where('bo_status', 'normal')->orderBy('bo_order_date', 'DESC')->findAll() : [];
        return $this->render('입고 처리', 'bag/create_bag_receiving', compact('orders'));
    }

    public function receivingStore()
    {
        $admin = new \App\Controllers\Admin\BagReceiving();
        $admin->initController($this->request, $this->response, service('logger'));
        $result = $admin->store();
        if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) {
            return redirect()->to(site_url('bag/purchase-inbound'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors'));
        }
        return redirect()->to(site_url('bag/purchase-inbound'))->with('success', '입고 처리되었습니다.');
    }

    // --- 판매 등록 ---
    public function saleCreate(): string
    {
        helper('admin');
        $lgIdx = $this->lgIdx();
        $shops = $lgIdx ? model(DesignatedShopModel::class)->where('ds_lg_idx', $lgIdx)->where('ds_state', 1)->findAll() : [];
        $kind     = model(CodeKindModel::class)->where('ck_code', 'O')->first();
        $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : [];
        return $this->render('판매 등록', 'bag/create_bag_sale', compact('shops', 'bagCodes'));
    }

    public function saleStore()
    {
        $admin = new \App\Controllers\Admin\BagSale();
        $admin->initController($this->request, $this->response, service('logger'));
        $result = $admin->store();
        if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) {
            return redirect()->to(site_url('bag/sales'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors'));
        }
        return redirect()->to(site_url('bag/sales'))->with('success', '판매 등록되었습니다.');
    }

    // --- 주문 접수 ---
    public function shopOrderCreate(): string
    {
        helper('admin');
        $lgIdx = $this->lgIdx();
        $shops = $lgIdx ? model(DesignatedShopModel::class)->where('ds_lg_idx', $lgIdx)->where('ds_state', 1)->findAll() : [];
        $kind     = model(CodeKindModel::class)->where('ck_code', 'O')->first();
        $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : [];
        return $this->render('주문 접수', 'bag/create_shop_order', compact('shops', 'bagCodes'));
    }

    public function shopOrderStore()
    {
        $admin = new \App\Controllers\Admin\ShopOrder();
        $admin->initController($this->request, $this->response, service('logger'));
        $result = $admin->store();
        if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) {
            return redirect()->to(site_url('bag/sales'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors'));
        }
        return redirect()->to(site_url('bag/sales'))->with('success', '주문 접수되었습니다.');
    }
}
