<?php

namespace MintyPHP\Repository\Mail;

use MintyPHP\DB;
use MintyPHP\Domain\Taxonomy\MailLogStatus;
use MintyPHP\Repository\Support\RepoQuery;

class MailLogRepository implements MailLogRepositoryInterface
{
    public function create(array $data): ?int
    {
        $id = DB::insert(
            'insert into mail_log (to_email, subject, template, status, created_at) values (?,?,?,?,NOW())',
            $data['to_email'],
            $data['subject'],
            $data['template'] ?? null,
            $data['status'] ?? MailLogStatus::Queued->value
        );
        return $id ? (int) $id : null;
    }

    public function markSent(int $id, ?string $providerMessageId = null): bool
    {
        $result = DB::update(
            'update mail_log set status = ?, sent_at = NOW(), provider_message_id = ?, error_message = NULL where id = ?',
            MailLogStatus::Sent->value,
            $providerMessageId,
            (string) $id
        );
        return $result !== false;
    }

    public function markFailed(int $id, string $errorMessage): bool
    {
        $result = DB::update(
            'update mail_log set status = ?, error_message = ? where id = ?',
            MailLogStatus::Failed->value,
            $errorMessage,
            (string) $id
        );
        return $result !== false;
    }

    public function listPaged(array $options): array
    {
        $search = trim((string) ($options['search'] ?? ''));
        $status = MailLogStatus::tryNormalize((string) ($options['status'] ?? ''))?->value ?? '';
        $createdFrom = trim((string) ($options['created_from'] ?? ''));
        $createdTo = trim((string) ($options['created_to'] ?? ''));

        $allowedOrder = ['id', 'created_at', 'sent_at', 'to_email', 'subject', 'status'];
        [$limit, $offset] = RepoQuery::sanitizeLimitOffset($options);
        [$order, $dir] = RepoQuery::sanitizeOrder($options, $allowedOrder, 'created_at', 'desc');

        $where = [];
        $params = [];
        RepoQuery::addLikeFilter($where, $params, ['to_email', 'subject', 'template'], $search);
        RepoQuery::addEqualsFilter($where, $params, $status, 'status = ?');
        if ($createdFrom !== '') {
            $where[] = 'created_at >= ?';
            $params[] = $createdFrom . ' 00:00:00';
        }
        if ($createdTo !== '') {
            $where[] = 'created_at <= ?';
            $params[] = $createdTo . ' 23:59:59';
        }

        $whereSql = $where ? (' where ' . implode(' and ', $where)) : '';
        $count = DB::selectValue('select count(*) from mail_log' . $whereSql, ...$params);
        $total = $count ? (int) $count : 0;

        $query = 'select id, to_email, subject, template, status, created_at, sent_at, error_message, provider_message_id from mail_log' .
            $whereSql .
            sprintf(' order by `%s` %s limit ? offset ?', $order, $dir);

        $queryParams = array_merge($params, [(string) $limit, (string) $offset]);
        $rows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge([$query], $queryParams));

        return [
            'total' => $total,
            'rows' => $this->unwrapList($rows),
        ];
    }

    public function find(int $id): ?array
    {
        $row = DB::selectOne(
            'select id, to_email, subject, template, status, created_at, sent_at, error_message, provider_message_id from mail_log where id = ? limit 1',
            (string) $id
        );
        return $this->unwrap($row);
    }

    private function unwrap(?array $row): ?array
    {
        if (!$row) {
            return null;
        }
        return $row['mail_log'] ?? null;
    }

    private function unwrapList(mixed $rows): array
    {
        if (!is_array($rows)) {
            return [];
        }

        $list = [];
        foreach ($rows as $row) {
            $mailLog = $row['mail_log'] ?? null;
            if (is_array($mailLog)) {
                $list[] = $mailLog;
            }
        }

        return $list;
    }
}
