<?php
namespace App\Repositories\Admin\Mail;

use Illuminate\Support\Facades\DB;

final class AdminMailRepository
{
    public function createBatch(array $row): int
    {
        DB::table('admin_mail_batches')->insert($row);
        return (int)DB::getPdo()->lastInsertId();
    }

    public function updateBatch(int $batchId, array $row): int
    {
        return DB::table('admin_mail_batches')->where('id', $batchId)->update($row);
    }

    public function findBatch(int $batchId): ?object
    {
        $b = DB::table('admin_mail_batches')->where('id',$batchId)->first();
        return $b ?: null;
    }

    public function listBatches(array $filters, int $perPage)
    {
        $q = DB::table('admin_mail_batches');

        if (!empty($filters['status'])) $q->where('status', $filters['status']);
        if (!empty($filters['send_mode'])) $q->where('send_mode', $filters['send_mode']);

        if (!empty($filters['date_from'])) $q->whereDate('created_at','>=',$filters['date_from']);
        if (!empty($filters['date_to']))   $q->whereDate('created_at','<=',$filters['date_to']);

        if (!empty($filters['q'])) {
            $kw = '%'.$filters['q'].'%';
            $q->where(function($w) use ($kw){
                $w->where('subject_raw','like',$kw)
                    ->orWhere('body_raw','like',$kw)
                    ->orWhere('from_email','like',$kw)
                    ->orWhere('admin_name','like',$kw)
                    ->orWhere('last_error','like',$kw);
            });
        }

        return $q->orderByDesc('id')->paginate($perPage)->withQueryString();
    }

    public function bulkInsertItems(int $batchId, array $rows): void
    {
        // rows: [ [batch_id, seq, to_email, ...], ... ]
        DB::table('admin_mail_batch_items')->insert($rows);
    }

    public function listItems(int $batchId, array $filters, int $perPage)
    {
        $q = DB::table('admin_mail_batch_items')->where('batch_id',$batchId);

        if (!empty($filters['status'])) $q->where('status',$filters['status']);
        if (!empty($filters['to'])) $q->where('to_email','like','%'.$filters['to'].'%');
        if (!empty($filters['q'])) {
            $kw = '%'.$filters['q'].'%';
            $q->where(function($w) use ($kw){
                $w->where('subject_final','like',$kw)->orWhere('body_final','like',$kw)->orWhere('last_error','like',$kw);
            });
        }

        return $q->orderBy('seq')->paginate($perPage)->withQueryString();
    }

    public function markBatchSending(int $batchId): void
    {
        DB::table('admin_mail_batches')->where('id',$batchId)->update([
            'status' => 'sending',
            'started_at' => now()->format('Y-m-d H:i:s'),
        ]);
    }

    public function pickDueScheduledBatches(int $limit=20): array
    {
        $rows = DB::table('admin_mail_batches')
            ->where('status','scheduled')
            ->whereNotNull('scheduled_at')
            ->where('scheduled_at','<=', now()->format('Y-m-d H:i:s'))
            ->orderBy('scheduled_at')
            ->limit($limit)
            ->get();

        return $rows ? $rows->all() : [];
    }

    public function setBatchQueued(int $batchId): void
    {
        DB::table('admin_mail_batches')->where('id',$batchId)->update(['status'=>'queued']);
    }

    public function countItemsByStatus(int $batchId): array
    {
        $rows = DB::table('admin_mail_batch_items')
            ->select('status', DB::raw('COUNT(*) as c'))
            ->where('batch_id',$batchId)
            ->groupBy('status')->get();

        $map = ['sent'=>0,'failed'=>0,'canceled'=>0,'skipped'=>0,'queued'=>0];
        foreach ($rows as $r) $map[$r->status] = (int)$r->c;
        return $map;
    }

    public function updateBatchCounts(int $batchId, array $counts, ?string $status=null, ?string $lastError=null): void
    {
        $row = [
            'sent_count' => (int)($counts['sent'] ?? 0),
            'failed_count' => (int)($counts['failed'] ?? 0),
            'canceled_count' => (int)(($counts['canceled'] ?? 0) + ($counts['skipped'] ?? 0)),
        ];
        if ($status) $row['status'] = $status;
        if ($lastError !== null) $row['last_error'] = $lastError;
        if (in_array($status, ['sent','partial','failed','canceled'], true)) {
            $row['finished_at'] = now()->format('Y-m-d H:i:s');
        }
        DB::table('admin_mail_batches')->where('id',$batchId)->update($row);
    }

    public function cancelBatch(int $batchId): void
    {
        DB::table('admin_mail_batches')->where('id',$batchId)->update([
            'status'=>'canceled',
            'finished_at'=>now()->format('Y-m-d H:i:s'),
        ]);

        DB::table('admin_mail_batch_items')
            ->where('batch_id',$batchId)
            ->whereIn('status',['queued'])
            ->update(['status'=>'canceled','last_error'=>'batch_canceled']);
    }

    public function resetFailedToQueued(int $batchId): int
    {
        return DB::table('admin_mail_batch_items')
            ->where('batch_id',$batchId)
            ->where('status','failed')
            ->update(['status'=>'queued','last_error'=>'','attempts'=>0]);
    }

    public function nextQueuedItems(int $batchId, int $limit=200): array
    {
        $rows = DB::table('admin_mail_batch_items')
            ->where('batch_id',$batchId)
            ->where('status','queued')
            ->orderBy('seq')
            ->limit($limit)
            ->get();

        return $rows ? $rows->all() : [];
    }

    public function updateItem(int $id, array $row): void
    {
        DB::table('admin_mail_batch_items')->where('id',$id)->update($row);
    }
}
