<?php

namespace App\Controllers;


use CodeIgniter\Controller;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;

/**
 * Class BaseController
 *
 * BaseController provides a convenient place for loading components
 * and performing functions that are needed by all your controllers.
 * Extend this class in any new controllers:
 *     class Home extends BaseController
 *
 * For security be sure to declare any new methods as protected or private.
 */
abstract class BaseController extends Controller
{
    /**
     * Instance of the main Request object.
     *
     * @var CLIRequest|IncomingRequest
     */
    protected $request;

    /**
     * An array of helpers to be loaded automatically upon
     * class instantiation. These helpers will be available
     * to all other controllers that extend BaseController.
     *
     * @var array
     */
    protected $helpers = ['Common'];

    /**
     * Be sure to declare properties for any property fetch you initialized.
     * The creation of dynamic property is deprecated in PHP 8.2.
     */
    // protected $session;

    /**
     * Constructor.
     */
    protected $_validation = null;
    protected $_model = null;
    protected $_session = null;
    protected $_viewPath = '';
    protected $_viewDatas = array();
    protected $_per_page = DEFAULTS['PERPAGE'];
    public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
    {
        // Do Not Edit This Line
        parent::initController($request, $response, $logger);
        // Preload any models, libraries, etc, here.
        // E.g.: $this->session = \Config\Services::session();
        $this->_session = \Config\Services::session();
        $this->_validation = \Config\Services::validation();
        $this->_viewDatas['session'] = $this->_session;
        //사용자 기본 Role 지정
        $this->_viewDatas[SESSION_NAMES['ISLOGIN']] = false;
        $this->_viewDatas['currentRoles'] = [DEFAULTS["ROLE"]];
        if ($this->_session->get(SESSION_NAMES['ISLOGIN'])) {
            $this->_viewDatas[SESSION_NAMES['ISLOGIN']] = true;
            $this->_viewDatas['auth'] = $this->_session->get(SESSION_NAMES['AUTH']);
            $currentRoles = explode(DEFAULTS['DELIMITER_ROLE'], $this->_viewDatas['auth'][AUTH_FIELDS['ROLE']]);
            $this->_viewDatas['currentRoles'] = is_array($currentRoles) ? $currentRoles : [DEFAULTS["ROLE"]];
        }
    }

    abstract public function getFields(string $action): array;
    abstract public function getFieldFilters(): array;
    //Field별 Rule용
    protected function getFieldRule(string $field, array $rules, string $action = ""): array
    {
        switch ($field) {
            default:
                $rules = $this->_model->getFieldRule($field, $rules, $action);
                break;
        }
        return $rules;
    }
    final public function getFieldRules(array $fields, string $action = ""): array
    {
        $rules = array();
        foreach ($fields as $field) {
            $rules = $this->getFieldRule($field, $rules, $action);
        }
        return $rules;
    }
    public function getFieldBatchFilters(): array
    {
        return $this->getFieldFilters();
    }
    //Field별 Form Option용
    public function getFieldFormOption(string $field): array
    {
        switch ($field) {
            default:
                $options = $this->_model->getFieldFOrmOption($field);
                break;
        }
        if (!is_array($options)) {
            throw new \Exception(__FUNCTION__ . "에서 {$this->_viewDatas['className']}의 Field:{$field}의 FormOptionData가 array가 아닙니다.\n" . var_export($options, true));
        }
        return $options;
    }
    final public function getFieldFormOptions(array $fields): array
    {
        $fieldFormOptions = array();
        foreach ($fields as $field) {
            if (!is_string($field)) {
                throw new \Exception(__FUNCTION__ . "에서 {$this->_viewDatas['className']}의 Field:{$field}가 string 아닙니다.\n" . var_export($fields, true));
            }
            $fieldFormOptions[$field] = $this->getFieldFormOption($field);
        }
        return $fieldFormOptions;
    }
    //Field별 Form Datas 처리용
    protected function getFieldFormData(string $field, $entity = null): array
    {
        switch ($field) {
            default:
                $value = $this->request->getVar($field);
                if (!is_null($value)) {
                    $this->_viewDatas['fieldDatas'][$field] = $value;
                }
                break;
        }
        return $this->_viewDatas['fieldDatas'];
    }

    //초기화
    protected function action_init(array $action_datas): void
    {
        switch ($action_datas['action']) {
            case 'insert_form':
                $action = 'insert';
                break;
            case 'update_form':
                $action = 'update';
                break;
            default:
                $action = $action_datas['action'];
                break;
        }
        $this->_viewDatas['fields']           = array_key_exists('fields', $action_datas) ? $action_datas['fields'] : $this->getFields($action);
        $this->_viewDatas['fieldRules']       = $this->getFieldRules($this->_viewDatas['fields'], $action);
        $this->_viewDatas['fieldFilters']     = $this->getFieldFilters();
        $this->_viewDatas['batchjobFilters']  = $this->getFieldBatchFilters();
        $this->_viewDatas['fieldFormOptions'] = $this->getFieldFormOptions($this->_viewDatas['fieldFilters']);
    }

    //Insert관련
    protected function insert_form_process()
    {
        $this->_viewDatas['forms'] = ['attributes' => ['method' => "post",], 'hiddens' => []];
    }
    final public function insert_form()
    {
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $this->insert_form_process();
            helper(['form']);
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return view($this->_viewPath . '/insert', ['viewDatas' => $this->_viewDatas]);
        } catch (\Exception $e) {
            log_message("error", $e->getMessage());
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with('return_message', $e->getMessage());
        }
    }
    protected function insert_validate()
    {
        //Upload된 파일 검증(photo)때문에 먼처 체크
        $this->_validation->setRules($this->_viewDatas['fieldRules']);
        if (!$this->_validation->withRequest($this->request)->run()) {
            throw new \Exception("{$this->_viewDatas['title']}의 검증 오류발생\n" . implode("\n", $this->_validation->getErrors()));
        }

        //fieldData 적용
        $this->_viewDatas['fieldDatas'] = array();
        foreach ($this->_viewDatas['fields'] as $field) {
            $this->_viewDatas['fieldDatas'] = $this->getFieldFormData($field);
        }
    }
    protected function insert_process()
    {
        return $this->_model->create($this->_viewDatas['fieldDatas']);
    }
    final public function insert()
    {
        //Transaction 시작
        $this->_model->transStart();
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $this->insert_validate();
            $entity = $this->insert_process();
            //Transaction Commit
            $this->_model->transComplete();
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 {$entity->getTitle()}의 " . __FUNCTION__ . " 완료하였습니다.");
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } catch (\Exception $e) {
            //Transaction Rollback
            $this->_model->transRollback();
            log_message("error", $e->getMessage());
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 " . __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return redirect()->back()->withInput();
        }
    }

    //Update관련
    protected function update_form_process($entity)
    {
        $this->_viewDatas['forms'] = ['attributes' => ['method' => "post",], 'hiddens' => []];
        return $entity;
    }
    final public function update_form($uid)
    {
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->_viewDatas['entity'] = $this->update_form_process($entity);
            helper(['form']);
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return view($this->_viewPath . '/update',  ['viewDatas' => $this->_viewDatas]);
        } catch (\Exception $e) {
            log_message("error", $e->getMessage());
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with('return_message', $e->getMessage());
        }
    }
    protected function update_validate($entity)
    {
        //Upload된 파일 검증(photo)때문에 먼처 체크
        $this->_validation->setRules($this->_viewDatas['fieldRules']);
        if (!$this->_validation->withRequest($this->request)->run()) {
            throw new \Exception("{$this->_viewDatas['title']}의 검증 오류발생\n" . implode("\n", $this->_validation->getErrors()));
        }

        //fieldData 적용
        $this->_viewDatas['fieldDatas'] = array();
        foreach ($this->_viewDatas['fields'] as $field) {
            $this->_viewDatas['fieldDatas'] = $this->getFieldFormData($field, $entity);
        }

        //변견된 데이터 Log로 남기기
        foreach ($this->_viewDatas['fieldDatas'] as $field => $value) {
            if ($field != "passwd") { //보안위험성이 있으므로 passwd는 Log에 남기지 않는다.
                log_message(
                    "info",
                    sprintf(
                        "{$field} 변경: ---원본--\n%s\n---변경---\n%s",
                        $entity->$field,
                        var_export($value, true)
                    )
                );
            }
        }
    }
    protected function update_process($entity)
    {
        return $this->_model->modify($entity, $this->_viewDatas['fieldDatas']);
    }
    final public function update($uid)
    {
        //Transaction 시작
        $this->_model->transStart();
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->update_validate($entity);
            $entity = $this->update_process($entity);
            //Transaction Commit
            $this->_model->transComplete();
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 {$entity->getTitle()}의 " . __FUNCTION__ . " 완료하였습니다.");
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } catch (\Exception $e) {
            //Transaction Rollback
            $this->_model->transRollback();
            log_message("error", $e->getMessage());
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 " . __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return redirect()->back()->withInput();
        }
    }

    //Reply관련
    protected function reply_form_process($entity)
    {
        $titleField = $this->_model->getTitleField();
        $entity->$titleField = "RE: " . $entity->$titleField;
        $this->_viewDatas['forms'] = ['attributes' => ['method' => "post",], 'hiddens' => []];
        return $entity;
    }
    final public function reply_form($uid)
    {
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->_viewDatas['entity'] = $this->reply_form_process($entity);
            helper(['form']);
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return view($this->_viewPath . '/reply',  ['viewDatas' => $this->_viewDatas]);
        } catch (\Exception $e) {
            log_message("error", $e->getMessage());
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with('return_message', $e->getMessage());
        }
    }
    protected function reply_validate($entity)
    {
        //Upload된 파일 검증(photo)때문에 먼처 체크
        $this->_validation->setRules($this->_viewDatas['fieldRules']);
        if (!$this->_validation->withRequest($this->request)->run()) {
            throw new \Exception("{$this->_viewDatas['title']}의 검증 오류발생\n" . implode("\n", $this->_validation->getErrors()));
        }

        //fieldData 적용
        $this->_viewDatas['fieldDatas'] = array();
        foreach ($this->_viewDatas['fields'] as $field) {
            $this->_viewDatas['fieldDatas'] = $this->getFieldFormData($field, $entity);
        }
    }
    protected function reply_process($entity)
    {
        return $this->_model->reply($entity, $this->_viewDatas['fieldDatas']);
    }
    final public function reply($uid)
    {
        //Transaction 시작
        $this->_model->transStart();
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->reply_validate($entity);
            $entity = $this->reply_process($entity);
            //Transaction Commit
            $this->_model->transComplete();
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 {$entity->getTitle()}의 " . __FUNCTION__ . " 완료하였습니다.");
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } catch (\Exception $e) {
            //Transaction Rollback
            $this->_model->transRollback();
            log_message("error", $e->getMessage());
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 " . __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return redirect()->back()->withInput();
        }
    }

    //Toggle 관련
    protected function toggle_validate($entity)
    {
        //Upload된 파일 검증(photo)때문에 먼처 체크
        $this->_validation->setRules($this->_viewDatas['fieldRules']);
        if (!$this->_validation->withRequest($this->request)->run()) {
            throw new \Exception("{$this->_viewDatas['title']}의 검증 오류발생\n" . implode("\n", $this->_validation->getErrors()));
        }

        //fieldData 적용
        $this->_viewDatas['fieldDatas'] = array();
        foreach ($this->_viewDatas['fields'] as $field) {
            $this->_viewDatas['fieldDatas'] = $this->getFieldFormData($field, $entity);
        }
    }
    protected function toggle_process($entity)
    {
        return $this->_model->modify($entity, $this->_viewDatas['fieldDatas']);
    }
    final public function toggle($uid, string $field)
    {
        //Transaction 시작
        $this->_model->transStart();
        try {
            $this->action_init(['action' => __FUNCTION__, 'fields' => [$field]]);
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->toggle_validate($entity);
            $entity = $this->toggle_process($entity);
            //Transaction Commit
            $this->_model->transComplete();
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 {$entity->getTitle()}의 " . __FUNCTION__ . " 완료하였습니다.");
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } catch (\Exception $e) {
            //Transaction Rollback
            $this->_model->transRollback();
            log_message("error", $e->getMessage());
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 " . __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        }
    }
    //Batchjob 관련
    protected function batchjob_validate($entity)
    {
        //Upload된 파일 검증(photo)때문에 먼처 체크
        $this->_validation->setRules($this->_viewDatas['fieldRules']);
        if (!$this->_validation->withRequest($this->request)->run()) {
            throw new \Exception("{$this->_viewDatas['title']}의 검증 오류발생\n" . implode("\n", $this->_validation->getErrors()));
        }

        //fieldData 적용
        $this->_viewDatas['fieldDatas'] = array();
        foreach ($this->_viewDatas['fields'] as $field) {
            $this->_viewDatas['fieldDatas'] = $this->getFieldFormData($field, $entity);
        }
    }
    protected function batchjob_process($entity)
    {
        return $this->_model->modify($entity, $this->_viewDatas['fieldDatas']);
    }
    final public function batchjob()
    {
        $uids      = array();
        $entitys   = array();
        $batchjobs = array();
        //Transaction 시작
        $this->_model->transStart();
        try {
            //fields 해당하는 field중 선택된 값이 있는경우만 fields로 정의
            $fields = array();
            foreach ($this->getFieldBatchFilters() as $field) {
                if ($this->request->getVar($field)) {
                    array_push($fields, $field);
                }
            }
            if (!is_array($fields) || count($fields) === 0) {
                throw new \Exception($this->_viewDatas['title'] . '에서 변경할 항목(field)이 선택되지 않았습니다.');
            }
            $this->action_init(['action' => __FUNCTION__, 'fields' => $fields]);
            $uids = $this->request->getVar('batchjob_uids') ?: throw new \Exception($this->_viewDatas['title'] . '에서 변경할 항목(uid)이 선택되지 않았습니다.');
            $cnt = 1;
            foreach ($uids as $uid) {
                try {
                    $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
                    $this->batchjob_validate($entity);
                    $entity = $this->batchjob_process($entity);
                    array_push($entitys, $this->_model->modify($entity, $this->_viewDatas['fieldDatas']));
                    array_push($batchjobs, "{$cnt}. {$uid}->{$entity->getTitle()}는 완료.");
                } catch (\Exception $e) {
                    array_push($batchjobs, "{$cnt}. {$uid}는 실패.");
                }
                $cnt++;
            }
            //Transaction Commit
            $this->_model->transComplete();
            $this->_session->setFlashdata(
                "return_message",
                sprintf("%s에서 총:%s개의 %s 완료하였습니다.", $this->_viewDatas['title'], count($entitys), __FUNCTION__,),
            );
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } catch (\Exception $e) {
            //Transaction Rollback
            $this->_model->transRollback();
            log_message("error", $e->getMessage());
            $this->_session->setFlashdata(
                "return_message",
                sprintf(
                    "총:%s개의 작업중 %s개는 성공하였지만 , %s개가 실패하여  %s 취소되었습니다.\n%s",
                    count($uids),
                    count($entitys),
                    count($uids) - count($entitys),
                    __FUNCTION__,
                    $e->getMessage(),
                ),
            );
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } finally {
            log_message('error', sprintf("---------batchjob 작업결과--------\n%s\n", implode("\n", $batchjobs)));
        }
    }

    //Delete 관련
    protected function delete_process($entity)
    {
        if (!$this->_model->delete($entity->getPrimaryKey())) {
            log_message("error", __FUNCTION__ . "에서 호출:" . $this->_model->getLastQuery());
            log_message("error", implode("\n", $this->_model->errors()));
            throw new \Exception(__FUNCTION__ . " 오류 발생.\n" . var_export($this->_model->errors(), true));
        }
        return $entity;
    }
    final public function delete($uid)
    {
        //Transaction 시작
        $this->_model->transStart();
        try {
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->delete_process($entity);
            //Transaction Commit
            $this->_model->transComplete();
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 {$entity->getTitle()}의 " . __FUNCTION__ . " 완료하였습니다.");
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        } catch (\Exception $e) {
            //Transaction Rollback
            $this->_model->transRollback();
            log_message("error", $e->getMessage());
            $this->_session->setFlashdata("return_message", "{$this->_viewDatas['title']}에서 " . __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/");
        }
    }

    //View 관련
    protected function view_process($entity)
    {
        $this->_viewDatas['forms'] = ['attributes' => ['method' => "post",], 'hiddens' => []];
        return $entity;
    }
    final public function view($uid)
    {
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            $this->_viewDatas['entity'] = $this->view_process($entity);
            helper(['form']);
            $this->_session->keepFlashdata(SESSION_NAMES['RETURN_URL']);
            return view($this->_viewPath . '/view', ['viewDatas' => $this->_viewDatas]);
        } catch (\Exception $e) {
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with('return_message', $e->getMessage());
        }
    }

    //Index 관련
    protected function index_process()
    {
        $this->_viewDatas['forms'] = ['attributes' => ['method' => "post",], 'hiddens' => []];
    }
    protected function index_condition()
    {
        //조건절 처리
        foreach ($this->_viewDatas['fieldFilters'] as $field) {
            $value = $this->request->getVar($field);
            $this->_model->setIndexFieldFilter($field, $this->request->getVar($field) ?: DEFAULTS['EMPTY']);
        }
        //검색어 처리
        $this->_viewDatas['word'] = $this->request->getVar('word') ?: DEFAULTS['EMPTY'];
        $this->_model->setIndexWordFilter($this->_viewDatas['word']);
        //검색일 처리
        $this->_viewDatas['start'] = $this->request->getVar('start') ?: DEFAULTS['EMPTY'];
        $this->_viewDatas['end'] = $this->request->getVar('end') ?: DEFAULTS['EMPTY'];
        $this->_model->setIndexDateFilter($this->_viewDatas['start'], $this->_viewDatas['end']);
    }
    //Totalcount 처리
    protected function index_total(): int
    {
        $this->index_process();
        $this->index_condition();
        $total = $this->_model->countAllResults();
        // echo dd($this->_model->getLastQuery());
        return $total;
    }
    //PageNation 처리
    protected function index_pagination($pager_group = 'default', int $segment = 0, $template = 'bootstrap_full'): string
    {
        //Page, Per_page필요부분
        $this->_viewDatas['page'] = (int)$this->request->getVar('page') ?: 1;
        $this->_viewDatas['per_page'] = (int)$this->request->getVar('per_page') ?: $this->_per_page;
        //줄수 처리용
        $this->_viewDatas['pageOptions'] = array("" => "줄수선택");
        for ($i = 10; $i <= $this->_viewDatas['total_count'] + $this->_viewDatas['per_page']; $i += 10) {
            $this->_viewDatas['pageOptions'][$i] = $i;
        }
        // 1.Views/Pagers/에 bootstrap_full.php,bootstrap_simple.php 생성
        // 2.app/Config/Pager.php/$templates에 'bootstrap_full => 'Pagers\bootstrap_full',
        // 'bootstrap_simple' => 'Pagers\bootstrap_simple', 추가
        $pager = \Config\Services::pager();
        // $this->_model->paginate($this->_viewDatas['per_page'], $pager_group, $this->_viewDatas['page'], $segment);
        $pager->makeLinks(
            $this->_viewDatas['page'],
            $this->_viewDatas['per_page'],
            $this->_viewDatas['total_count'],
            $template,
            $segment,
            $pager_group
        );
        $this->_viewDatas['page'] = $pager->getCurrentPage($pager_group);
        $this->_viewDatas['total_page'] = $pager->getPageCount($pager_group);
        return $pager->links($pager_group, $template);
    }
    protected function index_entitys(): array
    {
        $this->index_condition();
        if (array_key_exists('page', $this->_viewDatas)) {
            $this->_model->limit(
                $this->_viewDatas['per_page'],
                $this->_viewDatas['page'] * $this->_viewDatas['per_page'] - $this->_viewDatas['per_page']
            );
        }
        //Sorting 처리
        $this->_viewDatas['order_field'] = $this->request->getVar('order_field') ?: DEFAULTS['EMPTY'];
        $this->_viewDatas['order_value'] = $this->request->getVar('order_value') ?: DEFAULTS['EMPTY'];
        $orderBy                         = [];
        if ($this->_viewDatas['order_field'] && $this->_viewDatas['order_value']) {
            $orderBy = ["{$this->_viewDatas['order_field']} {$this->_viewDatas['order_value']}"];
        }
        return $this->_model->getEntitys([], $orderBy);
    }
    public function index()
    {
        try {
            helper(['form']);
            $this->action_init(['action' => __FUNCTION__]);
            foreach ($this->_viewDatas['fieldFilters'] as $field) {
                $this->_viewDatas[$field] = $this->request->getVar($field) ?: DEFAULTS['EMPTY'];
            }
            //URL처리
            $this->_viewDatas['uri'] = $this->request->getUri();
            //total 처리
            $this->_viewDatas['total_count'] = $this->index_total();
            //pagenation 처리
            $this->_viewDatas['pagination'] = $this->index_pagination();
            //모델 처리
            $this->_viewDatas['entitys'] = $this->index_entitys();
            // dd($this->_model->getLastQuery());
            //setting return_url to session flashdata
            $this->_session->setFlashdata(SESSION_NAMES['RETURN_URL'], current_url() . '?' . $this->request->getUri()->getQuery() ?: "");
            return view($this->_viewPath . '/index' . $this->request->getVar('v') ?: '', ['viewDatas' => $this->_viewDatas]);
        } catch (\Exception $e) {
            log_message("error", $e->getMessage());
            return alert_CommonHelper($e->getMessage(), "back");
            // return redirect()->back()->with('return_message', $e->getMessage());
        }
    }

    //Excel 관련
    final protected function spreadSheet(string $html)
    {
        // //HTML저장
        // file_put_contents($fileName . '.html', $html);

        //HTML Read
        $reader = new \PhpOffice\PhpSpreadsheet\Reader\Html();
        $spreadsheet = $reader->loadFromString($html);
        // from File의 경우
        // $spreadsheet = $reader->load($fileName . '.html');

        //Excel저장
        $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
        // $writer->save($fileName . '.xlsx');

        // //PDF저장
        // $writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
        // $writer->save($fileName . '.pdf');
        return $writer;
    }
    final public function excel()
    {
        try {
            $this->action_init(['action' => __FUNCTION__]);
            $this->_viewDatas['Entitys'] = $this->index_entitys();
            $html = view(
                $this->_viewPath . '/excel',
                ['viewDatas' => $this->_viewDatas]
            );
            //결과파일저장
            $fileName = sprintf(
                "%s/%s_%s",
                PATHS['EXCEL'],
                $this->_viewDatas['className'],
                date('Y-m-d_Hm')
            );
            $writer = $this->spreadSheet($html);
            $writer->save($fileName . '.xlsx');
            //Download시
            header("Content-Type: application/vnd.ms-excel");
            header(sprintf("Content-Disposition: attachment; filename=%s", urlencode($fileName)));
            header("Expires: 0");
            header("Cache-Control: must-revalidate");
            header("Pragma: public");
            header("Content-Length:" . filesize(PATHS['EXCEL'] . '/' . $fileName));
            // flush();
            // return readfile(PATHS['EXCEL'] . '/' . $fileName);
            return $writer->save('php://output');
        } catch (\Exception $e) {
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with('return_message', $e->getMessage());
        }
    }
    //File Download관련
    public function download_process($field, $entity)
    {
        list($filename, $uploaded_filename) = explode(DEFAULTS['DELIMITER_FILE'], $entity->$field);
        if (!is_file(PATHS['UPLOAD'] . "/" . $uploaded_filename)) {
            throw new \Exception("첨부파일이 확인되지 않습니다.\n");
        }
        return $this->response->download(PATHS['UPLOAD'] . "/" . $uploaded_filename, null)->setFileName(date("Ymd") . '_' . $filename);
    }
    final public function download(string $field, $uid)
    {
        try {
            $entity = $this->_model->getEntity([$this->_model->getPrimaryKey() => $uid]);
            return $this->download_process($field, $entity);
        } catch (\Exception $e) {
            return redirect()->to($this->_session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with('return_message', $e->getMessage());
        }
    }
}
