<?php

namespace Storeplugin\PDFInvoice\Framework\Fields\Types;

defined('ABSPATH') || exit;

use Storeplugin\PDFInvoice\Framework\Abstracts\AbstractField;
use Storeplugin\PDFInvoice\Framework\Utils\Utils;

class FileUploadField extends AbstractField
{
    private static bool $assets_enqueued = false;

    /**
     * Get the field type.
     *
     * @return string
     */
    public static function getType(): string
    {
        return 'file_upload';
    }

    /**
     * Render the field.
     *
     * @param array  $field
     * @param mixed  $value
     * @param string $prefix
     *
     * @return string
     */
    public function render(array $field, $value, string $prefix): string
    {
        $this->enqueueAssets();

        $value = (string) $value;
        $has_value = $value !== '';
        $isDisabled = $this->hasTruthyFlag($field, 'disabled');
        $isReadonly = !$isDisabled && $this->hasTruthyFlag($field, 'readonly');
        $isRequired = $this->hasTruthyFlag($field, 'required');
        $isLocked = $isDisabled || $isReadonly;

        $placeholder = $field['placeholder'] ?? 'No file selected';
        if (!is_string($placeholder) || $placeholder === '') {
            $placeholder = 'No file selected';
        }

        $button_label = $field['button_label'] ?? 'Upload File';
        if (!is_string($button_label) || $button_label === '') {
            $button_label = 'Upload File';
        }

        $remove_label = $field['remove_label'] ?? 'Remove';
        if (!is_string($remove_label) || $remove_label === '') {
            $remove_label = 'Remove';
        }

        $modal_title = $field['modal_title'] ?? 'Select a file';
        if (!is_string($modal_title) || $modal_title === '') {
            $modal_title = 'Select a file';
        }

        $modal_button = $field['modal_button'] ?? 'Use this file';
        if (!is_string($modal_button) || $modal_button === '') {
            $modal_button = 'Use this file';
        }

        $library_type = $field['library_type'] ?? '';
        if (!is_string($library_type)) {
            $library_type = '';
        }

        $allowed_extensions = Utils::normalizeList($field['allowed_extensions'] ?? [], true);
        $allowed_mime_types = Utils::normalizeList($field['allowed_mime_types'] ?? []);
        $max_file_size = Utils::normalizeByteSize($field['max_file_size'] ?? 0);
        $max_file_size_label = $max_file_size > 0 ? Utils::formatByteSize($max_file_size) : '';
        $empty_preview_label = $placeholder;
        $empty_preview_meta = $max_file_size_label !== ''
            ? 'Maximum allowed file size is ' . $max_file_size_label
            : 'Select a file';
        $preview_kind = $this->resolvePreviewKind($value, $library_type, $allowed_extensions, $allowed_mime_types);
        $preview_background = ($has_value && $preview_kind === 'image')
            ? 'url(' . $value . ')'
            : 'none';

        $invalid_format_message = $field['invalid_format_message'] ?? '';
        if (!is_string($invalid_format_message)) {
            $invalid_format_message = '';
        }

        $invalid_size_message = $field['invalid_size_message'] ?? '';
        if (!is_string($invalid_size_message)) {
            $invalid_size_message = '';
        }

        $wrapperClass = 'nxtf-file-upload';
        if ($isLocked) {
            $wrapperClass .= ' nxtf-file-upload-locked';
        }
        if ($isDisabled) {
            $wrapperClass .= ' nxtf-file-upload-disabled';
        }
        if ($isReadonly) {
            $wrapperClass .= ' nxtf-file-upload-readonly';
        }

        $wrapper_attrs = $this->buildAttributes([
            'class' => $wrapperClass,
            'data-file-upload' => '1',
            'data-file-has-preview' => $has_value ? '1' : '0',
            'data-file-preview-kind' => $preview_kind,
            'data-file-empty-label' => $empty_preview_label,
            'data-file-empty-meta' => $empty_preview_meta,
            'data-file-title' => $modal_title,
            'data-file-button-text' => $modal_button,
            'data-file-library' => $library_type !== '' ? $library_type : null,
            'data-file-extensions' => !empty($allowed_extensions) ? implode(',', $allowed_extensions) : null,
            'data-file-mime-types' => !empty($allowed_mime_types) ? implode(',', $allowed_mime_types) : null,
            'data-file-invalid-message' => $invalid_format_message !== '' ? $invalid_format_message : null,
            'data-file-max-bytes' => $max_file_size > 0 ? (string) $max_file_size : null,
            'data-file-max-label' => $max_file_size_label !== '' ? $max_file_size_label : null,
            'data-file-invalid-size-message' => $invalid_size_message !== '' ? $invalid_size_message : null,
        ]);

        $inputClass = trim($this->resolveClass($field, $this->getInputClasses()) . ' nxtf-file-upload-input');

        $input_attrs = $this->buildAttributes([
            'type' => 'text',
            'id' => $this->getFieldId($field),
            'name' => $this->getFieldName($field['id'], $prefix),
            'value' => $value,
            'class' => $inputClass,
            'placeholder' => $placeholder,
            'readonly' => true,
            'disabled' => $isDisabled ? true : null,
            'required' => $isRequired ? true : null,
            'data-file-input' => '1',
        ]);

        $uploadClass = 'nxtf-image-btn';
        if ($isLocked) {
            $uploadClass .= ' nxtf-image-btn--secondary--disabled';
        }

        $preview_attrs = $this->buildAttributes([
            'type' => 'button',
            'class' => $uploadClass,
            'data-file-button' => '1',
            'data-file-preview' => '1',
            'disabled' => $isLocked ? true : null,
            'tabindex' => '-1',
        ]);

        $upload_attrs = $this->buildAttributes([
            'type' => 'button',
            'class' => $uploadClass,
            'data-file-button' => '1',
            'disabled' => $isLocked ? true : null,
        ]);

        $remove_style = 'nxtf-image-btn nxtf-image-btn--secondary';
        if ($isLocked || !$has_value) {
            $remove_style .= ' nxtf-image-btn--secondary--disabled';
        }

        $remove_attrs = $this->buildAttributes([
            'type' => 'button',
            'class' => $remove_style,
            'data-file-remove' => '1',
            'disabled' => ($isLocked || !$has_value) ? true : null,
        ]);

        $previewDescription = $max_file_size_label !== ''
            ? 'Maximum allowed file size is'
            : 'File upload';
        $previewMeta = $max_file_size_label !== ''
            ? $max_file_size_label
            : 'Select a file';
        if (!$has_value) {
            $previewDescription = $empty_preview_label;
            $previewMeta = $empty_preview_meta;
        } elseif ($preview_kind === 'file') {
            $previewDescription = 'Selected file';
            $previewMeta = $this->extractFileLabelFromUrl($value);
        }

        return sprintf(
            '<div %1$s>
                    <div class="nxtf-file-upload-preview">
                        <input %2$s>
                        <button %3$s style="background-image: %8$s; background-size: cover; background-position: center;">
                            <span class="dashicons dashicons-open-folder" style="width: 37px; height: 37px;"></span>
                            <p class="nxtf-label-description">
                                <span class="nxtf-file-upload-copy-label">%9$s</span>
                                <span class="nxtf-file-upload-copy-meta">%10$s</span>
                            </p>
                        </button>
                    </div>
                    <div class="nxtf-image-actions">
                        <button %4$s>%5$s</button>
                        <button %6$s>%7$s</button>
                    </div>
                </div>',
            $wrapper_attrs,
            $input_attrs,
            $preview_attrs,
            $upload_attrs,
            \esc_html($button_label),
            $remove_attrs,
            \esc_html($remove_label),
            \esc_attr($preview_background),
            \esc_html($previewDescription),
            \esc_html($previewMeta)
        );
    }

    /**
     * Resolve whether the saved value should render as an image preview or generic file state.
     */
    private function resolvePreviewKind(string $value, string $libraryType, array $allowedExtensions, array $allowedMimeTypes): string
    {
        if ($value === '') {
            return 'none';
        }

        $extension = strtolower(pathinfo($this->extractPathFromUrl($value), PATHINFO_EXTENSION));
        if ($extension !== '') {
            return $this->isImageExtension($extension) ? 'image' : 'file';
        }

        if (strtolower($libraryType) === 'image' || $this->mimeRulesSuggestImage($allowedMimeTypes) || $this->extensionRulesSuggestImage($allowedExtensions)) {
            return 'image';
        }

        return 'file';
    }

    /**
     * Determine if the extension is a common image extension.
     */
    private function isImageExtension(string $extension): bool
    {
        return in_array($extension, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg', 'avif', 'ico', 'tif', 'tiff'], true);
    }

    /**
     * Determine if the MIME rules are image-only.
     *
     * @param array<int, string> $allowedMimeTypes
     */
    private function mimeRulesSuggestImage(array $allowedMimeTypes): bool
    {
        foreach ($allowedMimeTypes as $rule) {
            $rule = strtolower(trim((string) $rule));
            if ($rule === 'image' || strpos($rule, 'image/') === 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * Determine if the extension rules are image-only.
     *
     * @param array<int, string> $allowedExtensions
     */
    private function extensionRulesSuggestImage(array $allowedExtensions): bool
    {
        foreach ($allowedExtensions as $extension) {
            if ($extension === '') {
                continue;
            }

            if (!$this->isImageExtension(ltrim(strtolower((string) $extension), '.'))) {
                return false;
            }
        }

        return $allowedExtensions !== [];
    }

    /**
     * Extract a readable file name from the stored URL.
     */
    private function extractFileLabelFromUrl(string $url): string
    {
        $path = $this->extractPathFromUrl($url);
        $label = basename($path);
        $label = rawurldecode($label);

        return $label !== '' ? $label : 'File attached';
    }

    /**
     * Extract the path portion of a URL without query or fragment.
     */
    private function extractPathFromUrl(string $url): string
    {
        $path = (string) wp_parse_url($url, PHP_URL_PATH);

        return $path !== '' ? $path : $url;
    }

    /**
     * Enqueue assets.
     */
    private function enqueueAssets(): void
    {
        if (self::$assets_enqueued) {
            return;
        }

        self::$assets_enqueued = true;

        if (function_exists('wp_enqueue_media')) {
            \wp_enqueue_media();
        }
    }
}
