<?php

namespace App\Services;

class YahooNSEOutputHelper
{
    /**
     * @param  array<int, array<string, mixed>>  $quotes
     * @return array<string, mixed>
     */
    public function formatStocks(array $quotes): array
    {
        $rows = array_values(array_filter(array_map(fn (array $quote): array => $this->formatQuoteRow($quote), $quotes), function (array $row): bool {
            return $row['ticker'] !== '';
        }));

        return $this->formatRows($rows, 'Stocks list retrieved.');
    }

    /**
     * @param  array<string, mixed>  $chartResult
     * @return array<string, mixed>
     */
    public function formatStock(string $symbol, array $chartResult): array
    {
        $rows = [$this->formatChartRow($symbol, $chartResult)];

        return $this->formatRows($rows, 'Stock data retrieved.');
    }

    /**
     * @param  array<int, array<string, string>>  $rows
     * @return array<string, mixed>
     */
    public function formatRows(array $rows, string $message): array
    {
        return $this->wrap($rows, $message);
    }

    /**
     * @param  array<string, mixed>  $raw
     * @return array<string, string>
     */
    private function formatQuoteRow(array $raw): array
    {
        $price = $this->toFloat($raw['regularMarketPrice'] ?? null);
        $previousClose = $this->toFloat($raw['regularMarketPreviousClose'] ?? null);
        $change = $this->toFloat($raw['regularMarketChange'] ?? null) ?? (($price !== null && $previousClose !== null) ? $price - $previousClose : 0.0);
        $symbol = $this->toRapidSymbol((string) ($raw['symbol'] ?? ''));
        $name = (string) ($raw['shortName'] ?? $raw['longName'] ?? $symbol);
        $volume = (int) ($raw['regularMarketVolume'] ?? 0);

        return [
            'ticker' => $symbol,
            'name' => $name,
            'volume' => number_format(max($volume, 0)),
            'price' => $this->formatPrice($price),
            'change' => $this->formatSignedChange($change),
        ];
    }

    /**
     * @param  array<string, mixed>  $chartResult
     * @return array<string, string>
     */
    private function formatChartRow(string $requestedSymbol, array $chartResult): array
    {
        $meta = $chartResult['meta'] ?? [];
        $symbol = (string) ($meta['symbol'] ?? $requestedSymbol);
        $price = $this->toFloat($meta['regularMarketPrice'] ?? null);
        $previousClose = $this->toFloat($meta['chartPreviousClose'] ?? null);

        if ($price === null) {
            $price = $this->lastCloseFromChart($chartResult);
        }

        $change = (($price !== null && $previousClose !== null) ? $price - $previousClose : 0.0);
        $volume = $this->lastVolumeFromChart($chartResult);

        return [
            'ticker' => $this->toRapidSymbol($symbol),
            'name' => (string) ($meta['longName'] ?? $meta['shortName'] ?? $this->toRapidSymbol($symbol)),
            'volume' => number_format(max($volume, 0)),
            'price' => $this->formatPrice($price),
            'change' => $this->formatSignedChange($change),
        ];
    }

    /**
     * @param  array<int, array<string, string>>  $rows
     * @return array<string, mixed>
     */
    private function wrap(array $rows, string $message): array
    {
        return [
            'success' => true,
            'message' => $message,
            'data' => [
                'success' => true,
                'data' => $rows,
            ],
        ];
    }

    private function toRapidSymbol(string $symbol): string
    {
        return strtoupper((string) preg_replace('/\.NR$/i', '', trim($symbol)));
    }

    private function formatPrice(?float $value): string
    {
        return number_format($value ?? 0.0, 2, '.', '');
    }

    private function formatSignedChange(float $value): string
    {
        $prefix = $value >= 0 ? '+' : '';

        return $prefix.number_format($value, 2, '.', '');
    }

    private function toFloat(mixed $value): ?float
    {
        if (is_numeric($value)) {
            return (float) $value;
        }

        return null;
    }

    /**
     * @param  array<string, mixed>  $chartResult
     */
    private function lastCloseFromChart(array $chartResult): ?float
    {
        $closes = $chartResult['indicators']['quote'][0]['close'] ?? [];
        if (! is_array($closes) || $closes === []) {
            return null;
        }

        $last = end($closes);

        return $this->toFloat($last);
    }

    /**
     * @param  array<string, mixed>  $chartResult
     */
    private function lastVolumeFromChart(array $chartResult): int
    {
        $volumes = $chartResult['indicators']['quote'][0]['volume'] ?? [];
        if (! is_array($volumes) || $volumes === []) {
            return 0;
        }

        $last = end($volumes);

        return is_numeric($last) ? (int) $last : 0;
    }
}
