<?php
declare(strict_types=1);

namespace Autogedal\StockLog\Model\Alert;

use Magento\Framework\App\Area;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Store\Model\Store;
use Psr\Log\LoggerInterface;

class Notifier
{
    const XML_PATH_ENABLE_OOS       = 'autogedal_stocklog/alerts/enable_oos_alert';
    const XML_PATH_ENABLE_QTY_DROP  = 'autogedal_stocklog/alerts/enable_qty_drop_alert';
    const XML_PATH_QTY_DROP_THRESH  = 'autogedal_stocklog/alerts/qty_drop_threshold';
    const XML_PATH_QTY_LOW_THRESH   = 'autogedal_stocklog/alerts/qty_low_threshold';
    const XML_PATH_ALERT_RECIPIENTS = 'autogedal_stocklog/alerts/alert_recipients';
    const TEMPLATE_ALERT            = 'autogedal_stocklog_alert';

    private ScopeConfigInterface $scopeConfig;
    private TransportBuilder $transportBuilder;
    private LoggerInterface $logger;
    private TimezoneInterface $timezone;

    public function __construct(
        ScopeConfigInterface $scopeConfig,
        TransportBuilder $transportBuilder,
        LoggerInterface $logger,
        TimezoneInterface $timezone
    ) {
        $this->scopeConfig      = $scopeConfig;
        $this->transportBuilder = $transportBuilder;
        $this->logger           = $logger;
        $this->timezone         = $timezone;
    }

    public function checkAndNotify(
        string $sku,
        float $qtyBefore,
        float $qtyAfter,
        int $inStockBefore,
        int $inStockAfter,
        string $source
    ): void {
        try {
            $this->checkOosAlert($sku, $qtyBefore, $qtyAfter, $inStockBefore, $inStockAfter, $source);
            $this->checkQtyAlerts($sku, $qtyBefore, $qtyAfter, $source);
        } catch (\Throwable $e) {
            $this->logger->error('StockLog Notifier error for SKU ' . $sku . ': ' . $e->getMessage());
        }
    }

    private function checkOosAlert(
        string $sku,
        float $qtyBefore,
        float $qtyAfter,
        int $inStockBefore,
        int $inStockAfter,
        string $source
    ): void {
        if (!$this->scopeConfig->isSetFlag(self::XML_PATH_ENABLE_OOS)) {
            return;
        }
        if ($inStockBefore === 1 && $inStockAfter === 0) {
            $this->sendAlert(
                'Product went Out of Stock',
                $sku,
                sprintf('Qty: %.0f → %.0f | Source: %s', $qtyBefore, $qtyAfter, $source),
                self::XML_PATH_ALERT_RECIPIENTS
            );
        }
    }

    private function checkQtyAlerts(string $sku, float $qtyBefore, float $qtyAfter, string $source): void
    {
        if (!$this->scopeConfig->isSetFlag(self::XML_PATH_ENABLE_QTY_DROP)) {
            return;
        }

        $dropThreshold = (float)$this->scopeConfig->getValue(self::XML_PATH_QTY_DROP_THRESH);
        $drop = $qtyBefore - $qtyAfter;

        if ($dropThreshold > 0 && $drop > $dropThreshold) {
            $this->sendAlert(
                sprintf('Large Qty Drop (−%.0f)', $drop),
                $sku,
                sprintf('Qty: %.0f → %.0f | Source: %s', $qtyBefore, $qtyAfter, $source),
                self::XML_PATH_ALERT_RECIPIENTS
            );
        }

        $lowThreshold = (float)$this->scopeConfig->getValue(self::XML_PATH_QTY_LOW_THRESH);
        if ($lowThreshold > 0 && $qtyBefore >= $lowThreshold && $qtyAfter < $lowThreshold) {
            $this->sendAlert(
                sprintf('Qty dropped below threshold (%.0f)', $lowThreshold),
                $sku,
                sprintf('Qty: %.0f → %.0f | Source: %s', $qtyBefore, $qtyAfter, $source),
                self::XML_PATH_ALERT_RECIPIENTS
            );
        }
    }

    private function sendAlert(string $title, string $sku, string $detail, string $recipientsConfigPath): void
    {
        $recipients = $this->parseRecipients($recipientsConfigPath);
        if (empty($recipients)) {
            return;
        }

        $vars = ['alert_title' => $title, 'sku' => $sku, 'detail' => $detail];

        foreach ($recipients as $email) {
            try {
                $transport = $this->transportBuilder
                    ->setTemplateIdentifier(self::TEMPLATE_ALERT)
                    ->setTemplateOptions(['area' => Area::AREA_ADMINHTML, 'store' => Store::DEFAULT_STORE_ID])
                    ->setTemplateVars($vars)
                    ->setFrom('general')
                    ->addTo($email)
                    ->getTransport();
                $transport->sendMessage();
            } catch (\Throwable $e) {
                $this->logger->error('StockLog alert to ' . $email . ' failed: ' . $e->getMessage());
            }
        }
    }

    public function sendReport(array $templateVars, array $recipients): void
    {
        if (empty($recipients)) {
            return;
        }

        $templateVars = $this->buildReportTemplateVars($templateVars);

        foreach ($recipients as $email) {
            try {
                $transport = $this->transportBuilder
                    ->setTemplateIdentifier('autogedal_stocklog_report')
                    ->setTemplateOptions(['area' => Area::AREA_ADMINHTML, 'store' => Store::DEFAULT_STORE_ID])
                    ->setTemplateVars($templateVars)
                    ->setFrom('general')
                    ->addTo($email)
                    ->getTransport();
                $transport->sendMessage();
            } catch (\Throwable $e) {
                $this->logger->error('StockLog report to ' . $email . ' failed: ' . $e->getMessage());
            }
        }
    }

    /**
     * Convert array data into pre-rendered HTML strings so the email template
     * does not need the unsupported {{each}} directive.
     */
    private function buildReportTemplateVars(array $vars): array
    {
        $th = 'style="background:#f0f0f0;padding:8px 10px;text-align:left;border-bottom:2px solid #ddd;"';
        $td = 'style="padding:6px 10px;border-bottom:1px solid #eee;"';
        $table = 'style="width:100%;border-collapse:collapse;font-size:13px;margin-bottom:20px;"';

        $oosList   = $vars['oos_list']   ?? [];
        $topDrops  = $vars['top_drops']  ?? [];
        $bySource  = $vars['by_source']  ?? [];

        $oos_html = '';
        if (!empty($oosList)) {
            $oos_html = "<table $table><tr>"
                . "<th $th>SKU</th><th $th>Qty Before</th><th $th>Qty After</th><th $th>Source</th><th $th>Date</th>"
                . '</tr>';
            foreach ($oosList as $row) {
                $oos_html .= '<tr>'
                    . '<td ' . $td . ' style="color:#d9534f;font-weight:bold;padding:6px 10px;border-bottom:1px solid #eee;">' . htmlspecialchars((string)($row['sku'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['qty_before'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['qty_after'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['source'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars($this->formatDate((string)($row['created_at'] ?? ''))) . '</td>'
                    . '</tr>';
            }
            $oos_html .= '</table>';
        }

        $top_drops_html = '';
        if (!empty($topDrops)) {
            $top_drops_html = "<table $table><tr>"
                . "<th $th>SKU</th><th $th>Qty Before</th><th $th>Qty After</th><th $th>Drop</th><th $th>Source</th>"
                . '</tr>';
            foreach ($topDrops as $row) {
                $top_drops_html .= '<tr>'
                    . "<td $td>" . htmlspecialchars((string)($row['sku'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['qty_before'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['qty_after'] ?? '')) . '</td>'
                    . '<td style="color:#d9534f;font-weight:bold;padding:6px 10px;border-bottom:1px solid #eee;">−' . htmlspecialchars((string)($row['drop_amount'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['source'] ?? '')) . '</td>'
                    . '</tr>';
            }
            $top_drops_html .= '</table>';
        }

        $by_source_html = '';
        if (!empty($bySource)) {
            $by_source_html = "<table $table><tr>"
                . "<th $th>Source</th><th $th>Count</th>"
                . '</tr>';
            foreach ($bySource as $row) {
                $by_source_html .= '<tr>'
                    . "<td $td>" . htmlspecialchars((string)($row['source'] ?? '')) . '</td>'
                    . "<td $td>" . htmlspecialchars((string)($row['cnt'] ?? '')) . '</td>'
                    . '</tr>';
            }
            $by_source_html .= '</table>';
        }

        return [
            'report_title'   => $vars['report_title']   ?? '',
            'period'         => $vars['period']          ?? '',
            'since'          => $this->formatDate($vars['since'] ?? ''),
            'total'          => $vars['total']           ?? 0,
            'oos_count'      => $vars['oos_count']       ?? 0,
            'oos_html'       => $oos_html,
            'top_drops_html' => $top_drops_html,
            'by_source_html' => $by_source_html,
        ];
    }

    private function formatDate(string $utcDate): string
    {
        try {
            return $this->timezone->formatDateTime(
                new \DateTime($utcDate, new \DateTimeZone('UTC')),
                \IntlDateFormatter::SHORT,
                \IntlDateFormatter::SHORT
            );
        } catch (\Throwable $e) {
            return $utcDate;
        }
    }

    public function parseRecipients(string $configPath): array
    {
        $raw = $this->scopeConfig->getValue($configPath) ?? '';
        return array_values(array_filter(array_map('trim', explode(',', (string)$raw))));
    }
}
