<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

/**
 * PaymentLog Model
 * 
 * Stores comprehensive API interaction logs for debugging, auditing, and monitoring.
 * Records all requests and responses from MTN MoMo API calls with detailed metrics.
 * This model follows the SSHIA Laravel System conventions for data integrity.
 * 
 * @package PaymentConfigurationModule
 * @author SSHIA Development Team
 * 
 * @property int $id
 * @property string $type Type of API operation (collection/disbursement/status_check/test)
 * @property string $endpoint API endpoint URL called
 * @property array|null $request_payload JSON encoded request data (sanitized)
 * @property int|null $response_status HTTP response status code
 * @property array|null $response_body JSON encoded response data
 * @property string|null $transaction_reference External transaction reference ID
 * @property int|null $execution_time_ms Request execution time in milliseconds
 * @property string|null $error_message Error message if request failed
 * @property \Illuminate\Support\Carbon $created_at
 */
class PaymentLog extends Model
{
    use HasFactory;

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'payment_logs';

    /**
     * Indicates if the model should be timestamped.
     * 
     * Only created_at is used; logs are immutable and don't have updated_at.
     *
     * @var bool
     */
    public $timestamps = false;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'type',
        'endpoint',
        'request_payload',
        'response_status',
        'response_body',
        'transaction_reference',
        'execution_time_ms',
        'error_message',
        'created_at',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'request_payload' => 'array',
        'response_body' => 'array',
        'response_status' => 'integer',
        'execution_time_ms' => 'integer',
        'created_at' => 'datetime',
    ];

    /**
     * Log type constants for consistent reference.
     */
    public const TYPE_COLLECTION  = 'collection';
    public const TYPE_DISBURSEMENT = 'disbursement';
    public const TYPE_STATUS_CHECK = 'status_check';
    public const TYPE_TEST         = 'test';
    public const TYPE_CALLBACK     = 'callback';

    /**
     * Scope: Filter by log type.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $type
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfType($query, string $type)
    {
        return $query->where('type', $type);
    }

    /**
     * Scope: Filter by collection type.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeCollections($query)
    {
        return $query->where('type', self::TYPE_COLLECTION);
    }

    /**
     * Scope: Filter by disbursement type.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeDisbursements($query)
    {
        return $query->where('type', self::TYPE_DISBURSEMENT);
    }

    /**
     * Scope: Filter by test type.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeTests($query)
    {
        return $query->where('type', self::TYPE_TEST);
    }

    /**
     * Scope: Filter by transaction reference.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $reference
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeByReference($query, string $reference)
    {
        return $query->where('transaction_reference', $reference);
    }

    /**
     * Scope: Filter successful requests (2xx status codes).
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeSuccessful($query)
    {
        return $query->whereBetween('response_status', [200, 299]);
    }

    /**
     * Scope: Filter failed requests (4xx and 5xx status codes).
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeFailed($query)
    {
        return $query->where('response_status', '>=', 400);
    }

    /**
     * Scope: Filter by date range.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param \Illuminate\Support\Carbon $startDate
     * @param \Illuminate\Support\Carbon $endDate
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeDateRange($query, $startDate, $endDate)
    {
        return $query->whereBetween('created_at', [$startDate, $endDate]);
    }

    /**
     * Scope: Filter by today's logs.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeToday($query)
    {
        return $query->whereDate('created_at', today());
    }

    /**
     * Scope: Filter by this week's logs.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeThisWeek($query)
    {
        return $query->whereBetween('created_at', [
            now()->startOfWeek(),
            now()->endOfWeek()
        ]);
    }

    /**
     * Scope: Filter by this month's logs.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeThisMonth($query)
    {
        return $query->whereBetween('created_at', [
            now()->startOfMonth(),
            now()->endOfMonth()
        ]);
    }

    /**
     * Scope: Order by newest first.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeLatest($query)
    {
        return $query->orderBy('created_at', 'desc');
    }

    /**
     * Scope: Order by oldest first.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOldest($query)
    {
        return $query->orderBy('created_at', 'asc');
    }

    /**
     * Check if the log represents a successful request.
     *
     * @return bool
     */
    public function isSuccessful(): bool
    {
        return $this->response_status >= 200 && $this->response_status < 300;
    }

    /**
     * Check if the log represents a failed request.
     *
     * @return bool
     */
    public function isFailed(): bool
    {
        return $this->response_status >= 400;
    }

    /**
     * Check if the log has an error.
     *
     * @return bool
     */
    public function hasError(): bool
    {
        return !empty($this->error_message);
    }

    /**
     * Get the status badge color for display.
     *
     * @return string
     */
    public function getStatusColor(): string
    {
        if ($this->isSuccessful()) {
            return 'green';
        }

        if ($this->response_status >= 500) {
            return 'red';
        }

        if ($this->response_status >= 400) {
            return 'orange';
        }

        return 'gray';
    }

    /**
     * Get the type label for display.
     *
     * @return string
     */
    public function getTypeLabel(): string
    {
        return match($this->type) {
            self::TYPE_COLLECTION  => 'Collection',
            self::TYPE_DISBURSEMENT => 'Disbursement',
            self::TYPE_STATUS_CHECK => 'Status Check',
            self::TYPE_TEST        => 'Test Connection',
            self::TYPE_CALLBACK    => 'Callback',
            default                => ucfirst($this->type),
        };
    }

    /**
     * Create a new log entry.
     *
     * @param string $type
     * @param string $endpoint
     * @param array|null $requestPayload
     * @param int|null $responseStatus
     * @param array|null $responseBody
     * @param string|null $transactionReference
     * @param int|null $executionTime
     * @param string|null $errorMessage
     * @return self
     */
    public static function log(
        string $type,
        string $endpoint,
        ?array $requestPayload = null,
        ?int $responseStatus = null,
        ?array $responseBody = null,
        ?string $transactionReference = null,
        ?int $executionTime = null,
        ?string $errorMessage = null
    ): self {
        return static::create([
            'type' => $type,
            'endpoint' => $endpoint,
            'request_payload' => $requestPayload,
            'response_status' => $responseStatus,
            'response_body' => $responseBody,
            'transaction_reference' => $transactionReference,
            'execution_time_ms' => $executionTime,
            'error_message' => $errorMessage,
            'created_at' => now(),
        ]);
    }

    /**
     * Get statistics summary for dashboard.
     *
     * @param string|null $type Filter by type (optional)
     * @return array<string, mixed>
     */
    public static function getStatistics(?string $type = null): array
    {
        $query = static::query();

        if ($type) {
            $query->where('type', $type);
        }

        $total = $query->count();
        $successful = (clone $query)->successful()->count();
        $failed = (clone $query)->failed()->count();
        $avgExecutionTime = (clone $query)->avg('execution_time_ms');

        return [
            'total' => $total,
            'successful' => $successful,
            'failed' => $failed,
            'success_rate' => $total > 0 ? round(($successful / $total) * 100, 1) : 0,
            'avg_execution_time' => round($avgExecutionTime ?? 0),
        ];
    }
}
