<?php

declare(strict_types=1);

namespace PrettyLinks\Pro\Tools;

use PrettyLinks\Pro\Reports\SplitTestData;

/**
 * CSV export for a link's split-test report — one row per variant URL,
 * with a Status column ("Current" / "Removed") plus clicks / uniques (and
 * conversions / conversion rate when a goal link is configured). Column
 * headers mirror the on-screen variants table.
 *
 * Built on `AggregateCsvExporter`: rows come from `SplitTestData::variants()`
 * (the same composition the JSON view uses, minus the chart time-series),
 * and the base handles chunk stitching + injection escaping.
 *
 * Expected `$args`: `link_id` (int), `from` (string), `to` (string).
 */
class SplitTestCsvExporter extends AggregateCsvExporter
{
    /**
     * Split-test data composer.
     *
     * @var SplitTestData
     */
    private SplitTestData $data;

    /**
     * Memoized built payload keyed by the link_id/from/to signature.
     *
     * @var array<string, mixed>|null
     */
    private ?array $built = null;

    /**
     * Cache key for the memoized build.
     *
     * @var string
     */
    private string $builtKey = '';

    /**
     * Construct the exporter with its split-test data composer.
     *
     * @param SplitTestData $data Split-test data composer.
     */
    public function __construct(SplitTestData $data)
    {
        $this->data = $data;
    }

    /**
     * Column headers. Conversion columns appear only when a goal link is
     * configured (mirrors the on-screen table).
     *
     * @param  array<string, mixed> $args Export arguments.
     * @return string[]
     */
    protected function columns(array $args): array
    {
        return array_values($this->labels($this->hasGoal($args)));
    }

    /**
     * One row per variant, in the report's canonical order (current
     * variants first, then historical URLs alphabetically).
     *
     * @param  array<string, mixed> $args Export arguments.
     * @return array<int, array<string, mixed>>
     */
    protected function computeRows(array $args): array
    {
        $built = $this->report($args);
        if ($built === null || empty($built['splitTestEnabled'])) {
            return [];
        }

        $hasGoal  = $this->hasGoal($args);
        $labels   = $this->labels($hasGoal);
        $variants = is_array($built['variants']) ? $built['variants'] : [];

        $rows = [];
        foreach ($variants as $variant) {
            $status = !empty($variant['isCurrent'])
                ? __('Current', 'pretty-link-pro')
                : __('Removed', 'pretty-link-pro');
            $row = [
                $labels['url']     => (string) ($variant['url'] ?? ''),
                $labels['status']  => $status,
                $labels['clicks']  => (string) (int) ($variant['clicks'] ?? 0),
                $labels['uniques'] => (string) (int) ($variant['uniques'] ?? 0),
            ];
            if ($hasGoal) {
                $row[$labels['conversions']] = (string) (int) ($variant['conversions'] ?? 0);
                $row[$labels['convRate']]    = number_format((float) ($variant['convRate'] ?? 0), 2, '.', '');
            }
            $rows[] = $row;
        }
        return $rows;
    }

    /**
     * Semantic-key → translated header label map. Single source used by
     * both `columns()` and `computeRows()`.
     *
     * @param  boolean $hasGoal Whether to include the conversion columns.
     * @return array<string, string>
     */
    private function labels(bool $hasGoal): array
    {
        $labels = [
            'url'     => __('Variant', 'pretty-link-pro'),
            'status'  => __('Status', 'pretty-link-pro'),
            'clicks'  => __('All Clicks', 'pretty-link-pro'),
            'uniques' => __('Unique Clicks', 'pretty-link-pro'),
        ];
        if ($hasGoal) {
            $labels['conversions'] = __('Conversions', 'pretty-link-pro');
            $labels['convRate']    = __('Conversion Rate (%)', 'pretty-link-pro');
        }
        return $labels;
    }

    /**
     * Whether the report has a live goal link configured.
     *
     * @param array<string, mixed> $args Export arguments.
     */
    private function hasGoal(array $args): bool
    {
        $built = $this->report($args);
        return $built !== null && $built['goalLinkId'] !== null && (int) $built['goalLinkId'] > 0;
    }

    /**
     * Memoized split-test build for the given args.
     *
     * @param  array<string, mixed> $args Export arguments.
     * @return array<string, mixed>|null
     */
    private function report(array $args): ?array
    {
        $linkId = (int) ($args['link_id'] ?? 0);
        $from   = (string) ($args['from'] ?? '');
        $to     = (string) ($args['to'] ?? '');
        $key    = md5($linkId . '|' . $from . '|' . $to);
        if ($this->builtKey !== $key) {
            $this->built    = $this->data->variants($linkId, $from, $to);
            $this->builtKey = $key;
        }
        return $this->built;
    }
}
