<?php

namespace GriffinForms\Includes\MergeTokens\Resolvers;

use GriffinForms\Includes\MergeTokens\ResolverInterface;
use GriffinForms\Includes\Payments\CartBuilder;
use GriffinForms\Includes\Payments\SubmissionPaymentMeta;
use GriffinForms\Includes\Helpers\Currency;

class SubmissionResolver implements ResolverInterface
{
    public function resolve(array $token, array $context): ?string
    {
        $attr = strtolower((string) ($token['attr'] ?? ''));
        $submission = $context['submission'] ?? [];
        $submission_id = (int) ($submission['id'] ?? $context['submission_id'] ?? 0);
        $form_id = (int) ($submission['form_id'] ?? $context['form_id'] ?? 0);

        switch ($attr) {
            case 'id':
                return $submission_id > 0 ? (string) $submission_id : null;
            case 'position':
                return $this->resolvePosition($submission_id, $form_id);
            case 'time':
                return $this->resolveTime($submission);
            case 'data':
                return $this->renderSubmissionData($submission, $form_id);
            case 'attachments_count':
                return $this->resolveAttachmentsCount($submission_id);
            case 'attachments_size':
                return $this->resolveAttachmentsSize($submission_id);
            case 'payment_total':
                return $this->resolvePaymentTotal($submission_id, $submission, $form_id);
            case 'payment_breakdown':
                return $this->renderPaymentBreakdown($submission, $form_id);
            case 'payment_status':
                return $this->resolvePaymentStatus($submission);
            case 'edit_url':
                return $this->resolveEditUrl($context);
        }

        return null;
    }

    private function resolveEditUrl(array $context): ?string
    {
        $submission_id    = (int) ($context['submission_meta']['id'] ?? 0);
        $submission_token = (string) ($context['submission_meta']['public_token'] ?? '');

        if ($submission_id <= 0 || $submission_token === '') {
            return null;
        }

        $placement = \GriffinForms\Includes\Onboarding\PlacementService::getInstance();
        $url = $placement->getSubmissionEditUrl($submission_id, $submission_token);

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

    private function resolvePosition(int $submission_id, int $form_id): ?string
    {
        if ($submission_id <= 0 || $form_id <= 0) {
            return null;
        }

        global $wpdb;
        $table = \GriffinForms\Config::getInstance()->getTable('submission');
        $count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM %i WHERE form_id = %d AND id <= %d",
                $table,
                $form_id,
                $submission_id
            )
        );

        return $count !== null ? (string) (int) $count : null;
    }

    private function resolveTime(array $submission): ?string
    {
        $created = $submission['created'] ?? '';
        if ($created === '') {
            return null;
        }
        $timestamp = strtotime((string) $created);
        if ($timestamp <= 0) {
            return (string) $created;
        }

        $date_format = get_option('date_format');
        $time_format = get_option('time_format');
        return wp_date("{$date_format} {$time_format}", $timestamp);
    }

    private function resolveAttachmentsCount(int $submission_id): ?string
    {
        if ($submission_id <= 0) {
            return null;
        }
        $sql = \GriffinForms\Admin\Sql\Submissions::getInstance();
        return (string) $sql->getAttachmentCountBySubmissionId($submission_id);
    }

    private function resolveAttachmentsSize(int $submission_id): ?string
    {
        if ($submission_id <= 0) {
            return null;
        }
        $sql = \GriffinForms\Admin\Sql\Submissions::getInstance();
        $bytes = (int) $sql->getTotalAttachmentSizeBySubmissionId($submission_id);
        if (class_exists('\\GriffinForms\\Admin\\Units')) {
            return \GriffinForms\Admin\Units::getInstance()->formatBytes($bytes);
        }
        return (string) $bytes;
    }

    private function resolvePaymentStatus(array $submission): ?string
    {
        $status = $submission['payment_status'] ?? '';
        return $status !== '' ? (string) $status : null;
    }

    private function resolvePaymentTotal(int $submission_id, array $submission, int $form_id): ?string
    {
        $meta = SubmissionPaymentMeta::getInstance()->getMeta($submission_id);
        $currency_helper = Currency::getInstance();
        $submission_data = $submission['submission'] ?? [];
        $cart = CartBuilder::getInstance()->build($form_id, is_array($submission_data) ? $submission_data : []);

        $total = $cart['total'] ?? null;
        if ($total === null && !empty($meta['stripe']['display_amount'])) {
            $total = (float) $meta['stripe']['display_amount'];
        }

        $currency = $cart['currency'] ?? 'USD';
        if ($total === null) {
            return null;
        }

        return $currency_helper->formatAmount((float) $total, $currency);
    }

    private function renderSubmissionData(array $submission, int $form_id): string
    {
        $data = $submission['submission'] ?? [];
        if (!is_array($data) || empty($data)) {
            return '';
        }

        $rows = [];
        foreach ($data as $page_fields) {
            if (!is_array($page_fields)) {
                continue;
            }
            foreach ($page_fields as $field_id => $value) {
                $label = $this->resolveFieldLabel((int) $field_id);
                $values = $this->flattenValue($value);
                $rows[] = [
                    'label' => $label !== '' ? $label : ('Field ' . (int) $field_id),
                    'value' => implode(', ', $values),
                ];
            }
        }

        if (empty($rows)) {
            return '';
        }

        $html = '<table cellspacing="0" cellpadding="6" border="1" style="width:100%; border-collapse: collapse;">';
        foreach ($rows as $row) {
            $html .= '<tr>';
            $html .= '<td><strong>' . esc_html($row['label']) . '</strong></td>';
            $html .= '<td>' . esc_html($row['value']) . '</td>';
            $html .= '</tr>';
        }
        $html .= '</table>';

        return $html;
    }

    private function renderPaymentBreakdown(array $submission, int $form_id): string
    {
        $data = $submission['submission'] ?? [];
        $cart = CartBuilder::getInstance()->build($form_id, is_array($data) ? $data : []);
        $items = $cart['items'] ?? [];

        if (empty($items)) {
            return '';
        }

        $currency_helper = Currency::getInstance();
        $currency = $cart['currency'] ?? 'USD';

        $html = '<table cellspacing="0" cellpadding="6" border="1" style="width:100%; border-collapse: collapse;">';
        $html .= '<tr><th align="left">' . esc_html__('Item', 'griffinforms-form-builder') . '</th><th align="left">' . esc_html__('Qty', 'griffinforms-form-builder') . '</th><th align="left">' . esc_html__('Total', 'griffinforms-form-builder') . '</th></tr>';
        foreach ($items as $item) {
            $label = isset($item['label']) ? (string) $item['label'] : '';
            $qty = isset($item['quantity']) ? (int) $item['quantity'] : 0;
            $line_total = isset($item['subtotal']) ? (float) $item['subtotal'] : 0.0;

            $html .= '<tr>';
            $html .= '<td>' . esc_html($label) . '</td>';
            $html .= '<td>' . esc_html((string) $qty) . '</td>';
            $html .= '<td>' . esc_html($currency_helper->formatAmount($line_total, $currency)) . '</td>';
            $html .= '</tr>';
        }
        $html .= '</table>';

        return $html;
    }

    /**
     * @param mixed $value
     * @return array<int,string>
     */
    private function flattenValue($value): array
    {
        if (is_array($value)) {
            $out = [];
            foreach ($value as $entry) {
                $out = array_merge($out, $this->flattenValue($entry));
            }
            return $out;
        }

        if (is_scalar($value)) {
            return [(string) $value];
        }

        return [];
    }

    private function resolveFieldLabel(int $field_id): string
    {
        if ($field_id <= 0 || !class_exists('\\GriffinForms\\Items\\Field')) {
            return '';
        }
        $field = new \GriffinForms\Items\Field();
        $field->loadItem($field_id);

        $label = $field->getProp('label');
        if ($label === null || $label === '') {
            $label = $field->getProp('heading');
        }
        return (string) ($label ?? '');
    }
}
