using System.ComponentModel.DataAnnotations;

namespace EonaCat.LogStack.Status.Models;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

public enum MonitorType { TCP, UDP, AppLocal, AppRemote, HTTP, HTTPS, Ping }

public enum MonitorStatus { Unknown, Up, Down, Warning, Degraded }

public enum IncidentSeverity { Minor, Major, Critical }

public enum IncidentStatus { Investigating, Identified, Monitoring, Resolved }

public enum AlertRuleCondition { IsDown, IsUp, ResponseAboveMs, CertExpiresWithinDays }

public class Monitor
{
    public int Id { get; set; }
    [Required] public string Name { get; set; } = "";
    public string? Description { get; set; }
    public MonitorType Type { get; set; }
    public string Host { get; set; } = "";
    public int? Port { get; set; }
    public string? Url { get; set; }
    public string? ProcessName { get; set; }
    public int IntervalSeconds { get; set; } = 60;
    public int TimeoutMs { get; set; } = 5000;
    public bool IsActive { get; set; } = true;
    public bool IsPublic { get; set; } = true;
    public string? Tags { get; set; }
    public string? GroupName { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime? LastChecked { get; set; }
    public MonitorStatus LastStatus { get; set; } = MonitorStatus.Unknown;
    public double? LastResponseMs { get; set; }

    /// <summary>Number of consecutive failing checks since the monitor last went down.</summary>
    public int ConsecutiveFailures { get; set; } = 0;

    /// <summary>How many consecutive failures before the monitor is marked Down (default: 1).</summary>
    public int FailureThreshold { get; set; } = 1;

    /// <summary>Optional expected HTTP keyword in the response body (HTTP/HTTPS monitors).</summary>
    public string? ExpectedKeyword { get; set; }

    /// <summary>Optional expected HTTP status code (HTTP/HTTPS monitors, default: any 2xx/3xx).</summary>
    public int? ExpectedStatusCode { get; set; }

    public ICollection<MonitorCheck> Checks { get; set; } = new List<MonitorCheck>();
    public ICollection<AlertRule> AlertRules { get; set; } = new List<AlertRule>();
}

public class MonitorCheck
{
    public int Id { get; set; }
    public int MonitorId { get; set; }
    public Monitor? Monitor { get; set; }
    public DateTime CheckedAt { get; set; } = DateTime.UtcNow;
    public MonitorStatus Status { get; set; }
    public double ResponseMs { get; set; }
    public string? Message { get; set; }
}

public class CertificateEntry
{
    public int Id { get; set; }
    [Required] public string Name { get; set; } = "";
    [Required] public string Domain { get; set; } = "";
    public int Port { get; set; } = 443;
    public DateTime? ExpiresAt { get; set; }
    public DateTime? IssuedAt { get; set; }
    public string? Issuer { get; set; }
    public string? Subject { get; set; }
    public string? Thumbprint { get; set; }
    public bool IsPublic { get; set; } = true;
    public bool AlertOnExpiry { get; set; } = true;
    public int AlertDaysBeforeExpiry { get; set; } = 30;
    public DateTime? LastChecked { get; set; }
    public string? LastError { get; set; }
}

public class LogEntry
{
    public int Id { get; set; }
    public string Source { get; set; } = "system";
    public string Level { get; set; } = "info";
    public string Message { get; set; } = "";
    public string? Properties { get; set; }
    public string? Exception { get; set; }
    public DateTime Timestamp { get; set; } = DateTime.UtcNow;
    public string? TraceId { get; set; }
    public string? Host { get; set; }
}

/// <summary>
/// Represents a manually-posted or auto-generated incident that is displayed
/// on the public status page to communicate outages and maintenance.
/// </summary>
public class Incident
{
    public int Id { get; set; }
    [Required] public string Title { get; set; } = "";
    public string? Body { get; set; }
    public IncidentSeverity Severity { get; set; } = IncidentSeverity.Minor;
    public IncidentStatus Status { get; set; } = IncidentStatus.Investigating;
    public int? MonitorId { get; set; }
    public Monitor? Monitor { get; set; }
    public bool IsPublic { get; set; } = true;
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    public DateTime? ResolvedAt { get; set; }
    public ICollection<IncidentUpdate> Updates { get; set; } = new List<IncidentUpdate>();
}

/// <summary>
/// A timestamped update appended to an incident (visible on the public page).
/// </summary>
public class IncidentUpdate
{
    public int Id { get; set; }
    public int IncidentId { get; set; }
    public Incident? Incident { get; set; }
    public string Message { get; set; } = "";
    public IncidentStatus Status { get; set; }
    public DateTime PostedAt { get; set; } = DateTime.UtcNow;
}

/// <summary>
/// A configurable alert rule attached to a monitor or applied globally.
/// When the condition is met, a notification is dispatched (e-mail / webhook).
/// </summary>
public class AlertRule
{
    public int Id { get; set; }
    public int? MonitorId { get; set; }
    public Monitor? Monitor { get; set; }
    public AlertRuleCondition Condition { get; set; }
    /// <summary>Threshold value used by <see cref="AlertRuleCondition.ResponseAboveMs"/> and <see cref="AlertRuleCondition.CertExpiresWithinDays"/>.</summary>
    public double? ThresholdValue { get; set; }
    /// <summary>Webhook URL to POST a JSON payload to when the rule fires (optional).</summary>
    public string? WebhookUrl { get; set; }
    public bool IsEnabled { get; set; } = true;
    public DateTime? LastFiredAt { get; set; }
    /// <summary>Minimum minutes between repeated firings (0 = every check).</summary>
    public int CooldownMinutes { get; set; } = 10;
}

public class AppSettings
{
    public int Id { get; set; }
    public string Key { get; set; } = "";
    public string Value { get; set; } = "";
}

public class LogFilter
{
    public string? Level { get; set; }
    public string? Source { get; set; }
    public string? Search { get; set; }
    public DateTime? From { get; set; }
    public DateTime? To { get; set; }
    public int Page { get; set; } = 1;
    public int PageSize { get; set; } = 100;
}

public class DashboardStats
{
    public int TotalMonitors { get; set; }
    public int UpCount { get; set; }
    public int DownCount { get; set; }
    public int WarnCount { get; set; }
    public int UnknownCount { get; set; }
    public int CertCount { get; set; }
    public int CertExpiringSoon { get; set; }
    public int CertExpired { get; set; }
    public long TotalLogs { get; set; }
    public long ErrorLogs { get; set; }
    public double OverallUptime { get; set; }
    public int ActiveIncidents { get; set; }
    public int ResolvedIncidents { get; set; }
}

/// <summary>Uptime percentage over a configurable window.</summary>
public class UptimeReport
{
    public int MonitorId { get; set; }
    public string MonitorName { get; set; } = "";
    public double Uptime24h { get; set; }
    public double Uptime7d { get; set; }
    public double Uptime30d { get; set; }
    public int TotalChecks { get; set; }
    public int UpChecks { get; set; }
    public int DownChecks { get; set; }
    public double AvgResponseMs { get; set; }
}

/// <summary>Log volume aggregated per hour / day for charting.</summary>
public class LogStatsBucket
{
    public DateTime BucketStart { get; set; }
    public long Total { get; set; }
    public long Errors { get; set; }
    public long Warnings { get; set; }
}
