<?php

namespace App\Repositories;

use App\Models\EmailLog;
use Illuminate\Database\Eloquent\Builder;
use App\Support\Query;
use Illuminate\Support\Facades\DB;

class EmailLogRepository extends Repository
{
    public function __construct($event = null)
    {
        $this->for($event);
    }

    public function model(): ?EmailLog
    {
        return new EmailLog;
    }

    public function query($as = null)
    {
        $model = $this->model();
        return $model->newQuery();
    }

    public function selectColumns(): array
    {
        return [
            'email_logs.id',
            'email_logs.email_type',
            'email_logs.recipient',
            'email_logs.subject',
            'email_logs.status',
            'email_logs.sent_at',
            'email_logs.failed_at',
            'email_logs.failure_reason',
            'email_logs.retry_count',
            'email_logs.max_retries',
            'email_logs.created_at',
        ];
    }

    public function scope($arguments, $callback = null)
    {
        $query = $this->query()->select($this->selectColumns());
        $this->applyScope($query, $arguments);
        return $this->resolve($query, $arguments, $callback);
    }

    public function applyScope(Builder $query, $arguments): Builder
    {
        $this->applyEventScope($query, $arguments);
        $this->applyStatusScope($query, $arguments);
        $this->applyOrder($query, $arguments);
        $this->applySearch($query, $arguments);
        return $query;
    }

    public function applyEventScope(Builder $query, $arguments): Builder
    {
        if ($arguments->event) {
            $query->where('email_logs.event_id', '=', $arguments->event->id);
        }
        return $query;
    }

    public function applyStatusScope(Builder $query, $arguments): Builder
    {
        if ($arguments->status) {
            $query->where('email_logs.status', $arguments->status);
        }
        return $query;
    }

    public function applyOrder(Builder $query, Query $arguments): Builder
    {
        $columns = [
            'id' => 'email_logs.id',
            'email_type' => 'email_logs.email_type',
            'subject' => 'email_logs.subject',
            'status' => 'email_logs.status',
            'created_at' => 'email_logs.created_at',
            'failed_at' => 'email_logs.failed_at',
        ];

        $sorts = json_decode($arguments->sort, true) ?? [];
        foreach ($sorts as $sort => $method) {
            if (array_key_exists($sort, $columns)) {
                $query->orderBy($columns[$sort], $method);
            }
        }

        // Default order
        if (empty($sorts)) {
            $query->orderBy('email_logs.created_at', 'desc');
        }

        return $query;
    }

    public function applySearch(Builder $query, $arguments): Builder
    {
        if ($arguments->search) {
            $search = strtolower($arguments->search);
            $query->where(function ($query) use ($search) {
                $query->orWhere(DB::raw("lower(email_logs.recipient)"), 'like', "%{$search}%")
                      ->orWhere(DB::raw("lower(email_logs.subject)"), 'like', "%{$search}%")
                      ->orWhere(DB::raw("lower(email_logs.email_type)"), 'like', "%{$search}%")
                      ->orWhere(DB::raw("lower(email_logs.failure_reason)"), 'like', "%{$search}%");
            });
        }
        return $query;
    }

    public function listing($request, $paginate = true)
    {
        $arguments = $this->arguments($request);
        $query = $this->scope($arguments);
        
        return ($paginate && $arguments->paging != 'All') 
            ? $query->paginate($arguments->paging, ['*'], 'page', $arguments->page) 
            : $query->get();
    }

    public function fetchSingleEmailLog($id)
    {
        return EmailLog::with('event')->find($id);
    }

    public function getRetryableEmails($eventId)
    {
        return EmailLog::where('event_id', $eventId)
                      ->failed()
                      ->canRetry()
                      ->get();
    }
}