<?php

namespace GriffinForms\Admin\Html\Elements\Submission;

class FileUpload extends \GriffinForms\Admin\Html\Elements\Submission\Format
{
    /**
     * Extract an array of file tokens (sha1 hex) from a raw submission value.
     * Accepts single string, comma-separated string, or array of strings.
     *
     * @param mixed $raw
     * @return array<string>
     */
    protected function extractTokens($raw)
    {
        $candidates = [];
        if (is_array($raw)) {
            $candidates = $raw;
        } elseif (is_string($raw)) {
            $candidates = array_map('trim', explode(',', $raw));
        }
        $tokens = [];
        foreach ($candidates as $val) {
            if (!is_string($val)) { continue; }
            $val = trim($val);
            if ($val === '') { continue; }
            if (preg_match('/^[a-f0-9]{40}$/i', $val)) {
                $tokens[] = $val;
            }
        }
        return array_values(array_unique($tokens));
    }

    /**
     * Convert bytes to human-readable string using shared Units helper.
     */
    protected function formatBytesHuman($bytes)
    {
        $bytes = is_numeric($bytes) ? (int) $bytes : 0;
        if ($bytes <= 0) { return ''; }
        return \GriffinForms\Admin\Units::getInstance()->formatBytes($bytes);
    }

    /**
     * Format image dimensions as "{w}×{h}".
     */
    protected function formatDimensions($width, $height)
    {
        $w = is_numeric($width) ? (int) $width : 0;
        $h = is_numeric($height) ? (int) $height : 0;
        if ($w > 0 && $h > 0) {
            return $w . '×' . $h;
        }
        return '';
    }

    /**
     * Decide icon key based on MIME or filename extension.
     * Returns a semantic key that CSS can map to an icon (e.g., 'pdf', 'image', 'doc', 'file').
     */
    protected function iconKeyForMime($mime, $name = '')
    {
        $mime = is_string($mime) ? strtolower($mime) : '';
        $ext  = '';
        if (is_string($name) && $name !== '' && strpos($name, '.') !== false) {
            $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
        }
        if (strpos($mime, 'image/') === 0) return 'image';
        if ($mime === 'application/pdf' || $ext === 'pdf') return 'pdf';
        if (strpos($mime, 'audio/') === 0) return 'audio';
        if (strpos($mime, 'video/') === 0) return 'video';
        if (in_array($ext, array('doc','docx','odt','rtf','wps'), true)) return 'doc';
        if (in_array($ext, array('xls','xlsx','ods','csv'), true)) return 'xls';
        if (in_array($ext, array('ppt','pptx','odp','key'), true)) return 'ppt';
        if (in_array($ext, array('zip','rar','7z','gz','tar'), true)) return 'archive';
        if (in_array($ext, array('txt','md','markdown','log'), true)) return 'txt';
        if (in_array($ext, array('json','xml','yml','yaml','js','ts','css','html'), true)) return 'code';
        return 'file';
    }

    /**
     * Render left icon element. Uses <img> with URL built from icon key.
     * Accepts 'missing' as a semantic key and expects an icon missing.png to exist under frontend/images/fileicons/.
     */
    protected function renderIcon($icon_key)
    {
        $icon_key  = $icon_key ?: 'file';
        $root_url  = rtrim((string) $this->config->getRootUrl(), '/');
        $base_url  = $root_url . '/frontend/images/fileicons/';
        $icon_url  = $base_url . $icon_key . '.svg';

        echo '<div class="me-2 d-flex align-items-center" style="width:24px">'
           . '<img class="gf-file-icon" src="' . esc_url($icon_url) . '" alt="" width="20" height="20" loading="lazy">'
           . '</div>';
    }

    /**
     * Render name + meta (size and/or dimensions) stacked vertically.
     */
    protected function renderInfo($name, $size_human, $dimensions = '')
    {
        $name = (string) $name;
        $meta_parts = array();
        if ($size_human !== '') { $meta_parts[] = $size_human; }
        if ($dimensions !== '') { $meta_parts[] = $dimensions; }
        $meta_line = implode(' • ', $meta_parts);

        echo '<div class="me-2 text-truncate flex-fill">';
        echo '<div class="fw-medium text-truncate">' . esc_html($name) . '</div>';
        if ($meta_line !== '') {
            echo '<div class="text-muted small">' . esc_html($meta_line) . '</div>';
        }
        echo '</div>';
    }

    /**
     * Render right-side download button if URL is available.
     */
    protected function renderDownloadButton($url)
    {
        $url = is_string($url) ? $url : '';
        if ($url === '') { return; }
        echo '<a class="btn btn-outline-dark btn-sm" href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer">'
            . esc_html__('Download', 'griffinforms-form-builder') . '</a>';
    }

    protected function renderFileListItem($token, $sql)
    {
        $name = '';
        if (isset($sql) && method_exists($sql, 'getFileNameFromToken')) {
            $name = (string) $sql->getFileNameFromToken($token);
        }

        $row = $this->sql->fetchFileRowByToken($token);
        if (!$row || !is_array($row)) {
            echo '<li class="list-group-item d-flex justify-content-between align-items-center small">';
            // Left icon: show a dedicated missing icon key
            $this->renderIcon('missing');
            // Middle info: message only
            $this->renderInfo(esc_html__('This file no longer exists.', 'griffinforms-form-builder'), '');
            // No download button on the right for missing files
            echo '</li>';
            return;
        }
        
        $mime       = isset($row['mime']) ? (string) $row['mime'] : '';
        $size_human = isset($row['size_bytes']) ? $this->formatBytesHuman($row['size_bytes']) : '';
        $width      = isset($row['image_w']) ? $row['image_w'] : null;
        $height     = isset($row['image_h']) ? $row['image_h'] : null;
        $dimensions = $this->formatDimensions($width, $height);
        $url        = isset($row['url']) ? (string) $row['url'] : '';
        $icon_key   = $this->iconKeyForMime($mime, $name);
        $label      = $name !== '' ? $name : $token; // fallback to token if unresolved

        echo '<li class="list-group-item d-flex justify-content-between align-items-center small">';
        // Left icon
        $this->renderIcon($icon_key);
        // Middle info (name + size)
        $this->renderInfo($label, $size_human, $dimensions);
        // Right download button
        $this->renderDownloadButton($url);
        echo '</li>';
    }

    public function getHtml()
    {
        // Accept both array and scalar values; normalize to array for iteration
        if ($this->field_value === null || $this->field_value === '' || (is_array($this->field_value) && empty($this->field_value))) {
            return;
        }

        $values = is_array($this->field_value) ? $this->field_value : array($this->field_value);
        $sql = \GriffinForms\Admin\Sql\Submissions::getInstance();

        echo '<ul class="list-group">';
        foreach ($values as $raw_value) {
            $tokens = $this->extractTokens($raw_value);
            if (empty($tokens)) {
                continue;
            }

            foreach ($tokens as $token) {
                $this->renderFileListItem($token, $sql);
            }
            
        }
        echo '</ul>';
    }
}