<?php

namespace BitCode\BitFormPro\Admin\BfTable;

use BitCode\BitForm\Admin\Form\AdminFormHandler;
use BitCode\BitForm\Core\Form\FormManager;
use BitCode\BitFormPro\Admin\BfTable\Table;
use BitCode\BitForm\Core\Util\FieldValueHandler;
use BitCode\BitFormPro\Admin\BfTable\FrontendViewHandler;
use BitCode\BitForm\Core\Util\FileHandler;
use BitCode\BitForm\Core\Util\FrontendHelpers;

final class TableMarkUp
{
    private $_table;

    private $_tableId;
    private $_tableConfig;
    private $_formID;

    private $_actionsBtn;
    private $_accessControl;

    private $_fromPermission;

    private $_current_user_id;
    private $_current_user_roles;

    private $_uploadUrl = BITFORMS_UPLOAD_BASE_URL . '/' . 'uploads';

    // private $
    public function __construct($tableId)
    {
        $this->_tableId = $tableId;
        $this->_table = Table::gatATable(['id' => $tableId], null);
        $this->_tableConfig = \json_decode($this->_table->table_config);
        $this->_formID = $this->_table->form_id;
        $this->_accessControl = \json_decode($this->_table->access_control);
        $this->getCurrentUserInfo();
    }

    public function getFormId()
    {
        return $this->_formID;
    }

    public function setFormPermission($formPermission)
    {
        $this->_fromPermission = $formPermission;
    }

    private function getFormFields()
    {
        $adminFormHandler = new AdminFormHandler();
        $post = new \stdClass();
        $post = (object) [
            'id' => $this->_formID
        ];
        $getForm = $adminFormHandler->getAForm('', $post);
        $formContainer = $getForm['form_content'];

        return $formContainer['fields'];
    }

    private function getCurrentUserInfo()
    {
        $current_user_id = get_current_user_id();
        $current_user = get_userdata($current_user_id);
        $this->_current_user_roles = isset($current_user->roles) ? $current_user->roles : [];
        $this->_current_user_id = $current_user_id;
    }
    public function tableViewer()
    {
        // if (!$this->_accessControl->allowViewToPublic && !$this->_current_user_id) {
        //     $messageMarkup = sprintf(__('Yor cannot access #%s no. Table View', 'bitformpro'), $this->_tableId);
        //     $messageMarkup = apply_filters('bitform_filter_data_view_error_message', $messageMarkup, 'allowViewToPublic');
        //     return $messageMarkup;
        // }

        // if ($this->_current_user_id && (current_user_can('prevent_bitform_data_view') || !(current_user_can('read') || current_user_can('bitform_data_view')))) {
        //     $messageMarkup = sprintf(__('You do not have permission to access #%s no. Table View', 'bitformpro'), $this->_tableId);
        //     $messageMarkup = apply_filters('bitform_filter_data_view_error_message', $messageMarkup, 'checkViewCapability');
        //     return $messageMarkup;
        // }

        $tableConfig = $this->_tableConfig;
        $formID = $this->_formID;
        $tableId = $this->_tableId;

        $captionHTML = '';
        $theadHTML = '';
        $theadActionsHTML = '';
        $searchBarHTML = '';
        $paginationHTML = '';

        $columnsMap = $tableConfig->columnsMap;
        $this->_actionsBtn = $tableConfig->actionsBtn;
        $head = $this->_actionsBtn->head;

        $obj = new \stdClass();
        $obj->id = $formID;

        $entryRow = '';
        $canViewOthers = FrontendHelpers::is_current_user_can_access($formID, 'entryViewAccess', 'othersEntries');
        if (!$canViewOthers) {
            $obj->queryCondition = [
                'form_id' => $formID,
                'user_id' => get_current_user_id(),
            ];
        }
        $adminFormHandler = new AdminFormHandler();
        $getEntries = $adminFormHandler->getFormEntry('', $obj);
        if (is_wp_error($getEntries)) {
            return $getEntries->get_error_message();
        }
        $entries = $getEntries['entries'];
        $totalEntries = $getEntries['count'];

        // $search = 'K';
        // $filterArray = array_filter($entries, function ($entry) use ($search) {
        //   foreach ((array) $entry as $key => $value) {
        //     // partially match the search string regex, case insensitive search, return the row
        //     if (preg_match("/{$search}/i", $value)) {
        //       return $entry;
        //     }
        //   }
        // });


        $entryData = [];

        $this->rowMarkup($entries, $columnsMap, $entryRow, $entryData, $formID);

        $this->captionMarkup($captionHTML);

        $this->searchBarMarkup($searchBarHTML);

        $this->pagination($totalEntries, $paginationHTML);

        $formEntries = json_encode($entryData);

        $bfGlobals = <<<BFGLOBALS
      if(!window.bf_view_globals) { 
        window.bf_view_globals = {} 
      } 
      window.bf_view_globals = {...window.bf_view_globals, entries: {$formEntries}};

BFGLOBALS;

        FrontendViewHandler::addInlineScript($bfGlobals, 'bit-form-all-script', 'before');
        if (
            isset($head->show)
            && $head->show
            && ($this->isUserAllowedToEdit() || $this->isUserAllowedToView())
        ) {
            $theadActionsHTML = <<<THEAD_ACTIONS
      <th width="{$head->w}">
        {$head->thead}
      </th>
THEAD_ACTIONS;
        }

        foreach ($columnsMap as $column) {
            $theadHTML .= <<<THEAD
      <th width="{$column->w}" >
        {$column->thead}
      </th>
THEAD;
        }

        $tableHTML = <<<HTML
      <div class="bf{$formID}-{$tableId}-tbl-wrp bf-tbl-wrp">
        {$captionHTML}
        {$searchBarHTML}
        <div class="bf{$formID}-{$tableId}-tbl-cntnr">
            <table class="bf{$formID}-{$tableId}-tbl bf-tbl" >
          <thead class="bf{$formID}-{$tableId}-thead bf-thead" >
            <tr >
              {$theadHTML}
              {$theadActionsHTML}
            </tr>
          </thead>
          <tbody class="bf{$formID}-{$tableId}-tbody bf-tbody">
          {$entryRow}
          </tbody>
        </table>
        </div>
        {$paginationHTML}
      </div>
HTML;

        return $tableHTML;
    }

    private function isUserAllowedToEdit()
    {

        if (!$this->_current_user_id || current_user_can('prevent_bitform_data_edit')) {
            return false;
        }
        if (current_user_can('edit_posts') || current_user_can('bitform_data_edit')) {
            return true;
        }

        return false;
    }

    private function isUserAllowedToView()
    {
        if (isset($this->_accessControl->allowViewToPublic) && $this->_accessControl->allowViewToPublic) {
            return true;
        }

        if ($this->_current_user_id && (current_user_can('prevent_bitform_data_view') || !(current_user_can('read') || current_user_can('bitform_data_view')))) {
            return false;
        }

        return true;
    }

    private function actionHadrShowOrNotForAll()
    {
        $accessControl = $this->_accessControl;
        if (
            $accessControl->accessFor === 'all'
            && in_array($this->_current_user_roles[0], $accessControl->all->entryEdit)
        ) {
            return true;
        }
        return false;
    }

    private function actionHadrShowOrNotForUserIds()
    {
        $accessControl = $this->_accessControl;
        if (
            $accessControl->accessFor === 'user'
            && in_array($this->_current_user_id, $accessControl->user->ids)
        ) {
            return true;
        }
        return false;
    }


    private function getFileType($extension)
    {
        switch (strtolower($extension)) {

            case 'xbm':
            case 'tif':
            case 'pjp':
            case 'pjpeg':
            case 'svgz':
            case 'jpg':
            case 'jpeg':
            case 'ico':
            case 'tiff':
            case 'gif':
            case 'svg':
            case 'bmp':
            case 'png':
            case 'jfif':
            case 'webp':
                return 'image';

            case '7z':
            case 'arj':
            case 'deb':
            case 'pkg':
            case 'rar':
            case 'rpm':
            case 'gz':
            case 'z':
            case 'zip':
                return 'compressed';

            case 'key':
            case 'odp':
            case 'pps':
            case 'ppt':
            case 'pptx':
                return 'presentation';

            case '_rf_':
            case 'doc':
            case 'docx':
            case 'odt':
            case 'pdf':
            case 'rtf':
            case 'tex':
            case 'txt':
            case 'wks':
            case 'wps':
            case 'wpd':
                return 'document';

            case 'csv':
            case 'dat':
            case 'db':
            case 'dbf':
            case 'log':
            case 'mdb':
            case 'sav':
            case 'sql':
            case 'tar':
            case 'sqlite':
            case 'xml':
                return 'data';

            case 'opus':
            case 'flac':
            case 'webm':
            case 'weba':
            case 'wav':
            case 'ogg':
            case 'm4a':
            case 'mp3':
            case 'oga':
            case 'mid':
            case 'amr':
            case 'aiff':
            case 'wma':
            case 'au':
            case 'acc':
            case 'wpl':
                return 'audio';

            case 'ogm':
            case 'wmv':
            case 'mpg':
            case 'ogv':
            case 'mov':
            case 'asx':
            case 'mpeg':
            case 'mp4':
            case 'm4v':
            case 'avi':
            case '3gp':
            case 'flv':
            case 'mkv':
            case 'swf':
                return 'video';
            default:
                return 'other';
        }
    }



    public function isFileFldType($fk)
    {
        $fldType = ['advanced-file-up', 'signature', 'file-up'];

        $fields = $this->getFormFields();

        if (property_exists($fields, $fk) && in_array($fields->$fk->typ, $fldType)) {
            return true;
        }
        return false;
    }

    private function isValueFileType($fileName)
    {
        $fileExtension = $this->getFileExtension($fileName);
        return $this->getFileType($fileExtension) !== 'other';
    }

    private function isRepeaterFldType($fk)
    {
        $fields = $this->getFormFields();

        if (property_exists($fields, $fk) && $fields->$fk->typ === 'repeater') {
            return true;
        }
        return false;
    }



    private function getCleanedFieldKey($key)
    {
        return preg_replace('/\${([a-zA-Z0-9]+-\d+)}/', '$1', $key);
    }

    public function rowMarkup($entries, $columnsMap, &$entryRow, &$entryData, $formID)
    {

        // $this->isImgFldType('signature');
        foreach ($entries as $entry) {



            $row = [];
            $entryRow .= "<tr>";

            $resourceUrl = $this->createResourceUrl($entry->entry_id);
            foreach ($columnsMap as $column) {

                $value = FieldValueHandler::replaceFieldWithValue($column->fk, (array)$entry, $formID);
                // error_log(print_r($value, true));
                $value = FieldValueHandler::changeImagePathInHTMLString($value, $resourceUrl);
                $value = FieldValueHandler::changeHrefPathInHTMLString($value, $resourceUrl);
                // error_log(print_r($value, true));


                $cleanedFieldKey = $this->getCleanedFieldKey($column->fk);

                $td = "<td>";

                if ($this->isFileFldType($cleanedFieldKey)) {
                    $td .= $this->fileMarkup($value, $entry->entry_id);
                } else {
                    $v = is_string($value) ? json_decode($value, true) : $value;

                    if ($v && is_array($v)) {
                        $mrkup = implode(', ', $v);

                        $td .= $mrkup;
                    } else {
                        // show value (showing original value as json_decode returns null for plain string)
                        $td .= $value;
                    }
                }

                $td .= "</td>";
                $entryRow .= $td;
                $row[$column->fk] = $value;
            }
            $entryRow .= $this->actionButtonMarkup($entry->entry_id);
            $entryData[$entry->entry_id] = $row;
            $entryRow .= "</tr>";
        }
    }


    private function getFileExtension($fileName)
    {

        return strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
    }

    private function repeaterMarkup($repeaterValue, $entry_id)
    {
        $newValue = gettype($repeaterValue) === 'string' ? json_decode($repeaterValue, true) : $repeaterValue;
        if (is_array($newValue)) {

            $table = "<table style='width:100%'>";
            $table .= "<tr>";
            foreach ([$newValue[0]] as $val) {
                foreach ($val as $k => $v) {
                    $fields = $this->getFormFields()->$k;
                    $header =  $fields->lbl ?? $fields->fieldName ?? $fields->typ ?? $k;
                    $table .= "<th style='text-align:left; white-space:nowrap'>{$header}</th>";
                }
            }
            $table .= "</tr>";

            foreach ($newValue as $repeatedValue) {


                $table .= "<tr>";
                foreach ($repeatedValue as $key => $value) {

                    $table .= "<td>";

                    $cleanedFieldKey = $this->getCleanedFieldKey($key);

                    // $table .= $cleanedFieldKey;
                    if ($this->isFileFldType($cleanedFieldKey)) {
                        // show file markup

                        $table .=  $this->fileMarkup($value, $entry_id);
                    } else {
                        // as we are checking field type with key deleted field key might get past the fileTyp check. So checking if the value is file type by it's extension
                        if (is_array($value)) {
                            $mrkup = "";
                            foreach ($value as $val) {
                                if ($this->isValueFileType($val)) {
                                    $mrkup .= $this->fileMarkup($val, $entry_id);
                                } else {
                                    $mrkup .= "<span>{$val}" . (end($value) !== $val ? ', ' : '') . "</span>";
                                }
                            };
                            $table .= $mrkup;
                        } else {
                            // show value
                            $table .= $this->isValueFileType($value) ? $this->fileMarkup($value, $entry_id) : $value;
                        }
                    }
                    $table .=  "</td>";
                }
                $table .=  "</tr>";
            }
            $table .= "</table>";
            return $table;
        } else {
            return "<table></table>";
        }
    }

    private function isImageFile($fileName)
    {
        $extension = $this->getFileExtension($fileName);
        return $this->getFileType($extension) === 'image';
    }


    private function imgMarkup($fileName, $entryId)
    {
        $imgUrl = $this->createResourceUrl($entryId) . $fileName;

        return "<img src='{$imgUrl}' alt='{$fileName}' display:block' width='250'/>";
    }
    private function anchorMarkup($fileName, $entryId)
    {
        $fileUrl = $this->createResourceUrl($entryId) . $fileName;

        return "<a href={$fileUrl} target='_blank' rel='noopener noreferrer' style='color:blue; display:block'>{$fileName}</a>";
    }

    private function createResourceUrl($entry_id)
    {
        $resourceUrl = '';
        if (method_exists(FileHandler::class, 'getEntriesFileUploadURL')) {
            $resourceUrl = FileHandler::getEntriesFileUploadURL($this->_formID, $entry_id) . '/';
        } else {
            $resourceUrl = $this->_uploadUrl . '/' . $this->_formID . '/' . $entry_id . '/';
        }
        return $resourceUrl;
    }


    private function fileMarkup($value, $entry_id)
    {

        $newVal = gettype($value) === 'string' ? json_decode($value) : $value;

        if (is_array($newVal)) {
            $fileMarkup = '';

            foreach ($newVal as $fileName) {

                $fileMarkup .= $this->isImageFile($fileName) ? $this->imgMarkup($fileName, $entry_id) : $this->anchorMarkup($fileName, $entry_id);
            }
            return $fileMarkup;
        } else {

            $markup = '';
            // instead of hyperlink just returned the value for file fld typ from inside repeater as it's joined with comma
            if (!$this->isValueFileType($value)) {
                $markup .= $value;
                return $markup;
            }
            if ($this->isImageFile($value)) {
                if ($value === 'signature-failed.png') {
                    $markup .= "<img  style='width: 100% ; display:block' />";
                } else {
                    $markup .= $this->imgMarkup($value, $entry_id);
                }
            } else {
                $markup .= $this->anchorMarkup($value, $entry_id);
            }
            return $markup;
        }
    }



    public function actionButtonMarkup($entryId)
    {
        $actionsBtn = $this->_actionsBtn;
        $accessControl = $this->_accessControl;

        $html = '';
        if (isset($actionsBtn->head->show) && $actionsBtn->head->show && ($this->isUserAllowedToEdit() || $this->isUserAllowedToView())) {
            $html .= "<td><div class='bf{$this->_formID}-{$this->_tableId}-tbl-action-btns bf-tbl-action-btns'>";
            $editButton = $actionsBtn->editButton;
            $viewButton = $actionsBtn->viewButton;

            if (
                $editButton->show &&
                $this->isUserAllowedToEdit()
            ) {
                $html .= <<<EDIT_BTN
                          <a class="bf{$this->_formID}-{$this->_tableId}-tbl-edit-btn bf-tbl-edit-btn" href="{$editButton->slug}?bf_entry_id={$entryId}">
                            {$actionsBtn->editButton->btnTxt}
                          </a>
EDIT_BTN;
            }

            if (
                $viewButton->show &&
                $this->isUserAllowedToView()
            ) {
                $html .= <<<VIEW_BTN
                            <a class="bf{$this->_formID}-{$this->_tableId}-tbl-view-btn bf-tbl-view-btn" href="{$viewButton->slug}?bf_entry_id={$entryId}">
                              {$actionsBtn->viewButton->btnTxt}
                            </a>
VIEW_BTN;
            }
            //       if (
            //         $editButton->show
            //         && $accessControl->accessFor === 'all' &&
            //         in_array($this->_current_user_roles[0], $accessControl->all->entryEdit)
            //       ) {
            //         $html .= <<<EDIT_BTN
            //         <a class="bf{$this->_formID}-{$this->_tableId}-tbl-edit-btn bf-tbl-edit-btn" href="{$editButton->slug}?bf_entry_id={$entryId}">
            //           {$actionsBtn->editButton->btnTxt}
            //         </a>
            // EDIT_BTN;
            //       }
            //             if (
            //                 $viewButton->show
            //                 && $accessControl->accessFor === 'all' &&
            //                 in_array($this->_current_user_roles[0], $accessControl->all->singleEntryDetailsView)
            //             ) {
            //                 $html .= <<<VIEW_BTN
            //         <a class="bf{$this->_formID}-{$this->_tableId}-tbl-view-btn bf-tbl-view-btn" href="{$viewButton->slug}?bf_entry_id={$entryId}">
            //           {$actionsBtn->viewButton->btnTxt}
            //         </a>
            // VIEW_BTN;
            //             }
            $html .= '</div></td>';
        }
        return $html;
    }

    private function captionMarkup(&$captionHTML)
    {
        $tableConfig = $this->_tableConfig;
        if (isset($tableConfig->caption)) {
            $caption = $tableConfig->caption;
            $captionHTML = <<<CAPTION
        <div class="bf{$this->_formID}-{$this->_tableId}-tbl-caption bt-tbl-caption">
         {$caption}
        </div>
CAPTION;
        }
    }

    private function searchBarMarkup(&$searchBarHTML)
    {
        $searchBarHTML = <<<HTML
      <div class="bf{$this->_formID}-{$this->_tableId}-tbl-top-bar bf-tbl-top-bar">
        <label aria-label="search-bar" htmlFor="search-box bf-tbl-serc-lbl">
          Search
          <input
            id="search-box"
            class="bf{$this->_formID}-{$this->_tableId}-serc-bx -bf-tbl-serc-bx"
            type="text"
            name="search"
          />
        </label>
      </div>
HTML;
    }

    private function pagination($totalEntries, &$paginationHTML)
    {
        $formID = $this->_formID;
        $tableId = $this->_tableId;

        $paginationHTML = <<<HTML
      <div class="bf{$formID}-{$tableId}-tbl-footer bf-tbl-footer">
        <span>Total Response {$totalEntries}</span>
        <div class="gn">
          <button class="bf{$formID}-{$tableId}-pgn-btn bf-tbl-pgn-btn" data-page="start" type="button">&#171;</button>
          <button class="bf{$formID}-{$tableId}-pgn-btn bf-tbl-pgn-btn" data-page="previous" type="button">&#8249;</button>
          <button class="bf{$formID}-{$tableId}-pgn-btn bf-tbl-pgn-btn" data-page="next" type="button">&#8250;</button>
          <button class="bf{$formID}-{$tableId}-pgn-btn bf-tbl-pgn-btn" data-page="end" type="button">&#187;</button>
          <span>
            Page 
            <span class="bf{$formID}-{$tableId}-curr-page bf-tbl-curr-page">1</span> of 
            <span class="bf{$formID}-{$tableId}-total-page bf-tbl-total-page">10</span>
          </span>
          <select class="bf{$formID}-{$tableId}-tbl-pgn-slt bf-tbl-pgn-slt" name="limit" id="limit">
            <option value="10">10</option>
            <option value="20">20</option>
            <option value="30">30</option>
            <option value="40">40</option>
            <option value="50">50</option>
          </select>
        </div>
      </div>
HTML;
    }
}
