/// Synor Hosting SDK Types for Flutter
///
/// Decentralized web hosting with domain management, DNS, and deployments.
library synor_hosting_types;

// ==================== Config ====================

/// Hosting configuration
class HostingConfig {
  final String apiKey;
  final String endpoint;
  final Duration timeout;
  final int retries;
  final bool debug;

  const HostingConfig({
    required this.apiKey,
    this.endpoint = 'https://hosting.synor.io/v1',
    this.timeout = const Duration(seconds: 60),
    this.retries = 3,
    this.debug = false,
  });
}

// ==================== Domain Types ====================

/// Domain status
enum DomainStatus { pending, active, expired, suspended }

/// Domain information
class Domain {
  final String name;
  final DomainStatus status;
  final String owner;
  final DateTime registeredAt;
  final DateTime expiresAt;
  final bool autoRenew;
  final DomainRecord? records;

  const Domain({
    required this.name,
    required this.status,
    required this.owner,
    required this.registeredAt,
    required this.expiresAt,
    required this.autoRenew,
    this.records,
  });

  factory Domain.fromJson(Map<String, dynamic> json) => Domain(
        name: json['name'] as String,
        status: DomainStatus.values.firstWhere(
            (e) => e.name == json['status'],
            orElse: () => DomainStatus.pending),
        owner: json['owner'] as String,
        registeredAt: DateTime.fromMillisecondsSinceEpoch(json['registeredAt'] as int),
        expiresAt: DateTime.fromMillisecondsSinceEpoch(json['expiresAt'] as int),
        autoRenew: json['autoRenew'] as bool? ?? false,
        records: json['records'] != null ? DomainRecord.fromJson(json['records']) : null,
      );
}

/// Domain record
class DomainRecord {
  final String? cid;
  final List<String>? ipv4;
  final List<String>? ipv6;
  final String? cname;
  final List<String>? txt;
  final Map<String, String>? metadata;

  const DomainRecord({
    this.cid,
    this.ipv4,
    this.ipv6,
    this.cname,
    this.txt,
    this.metadata,
  });

  factory DomainRecord.fromJson(Map<String, dynamic> json) => DomainRecord(
        cid: json['cid'] as String?,
        ipv4: (json['ipv4'] as List?)?.cast<String>(),
        ipv6: (json['ipv6'] as List?)?.cast<String>(),
        cname: json['cname'] as String?,
        txt: (json['txt'] as List?)?.cast<String>(),
        metadata: (json['metadata'] as Map?)?.cast<String, String>(),
      );

  Map<String, dynamic> toJson() => {
        if (cid != null) 'cid': cid,
        if (ipv4 != null) 'ipv4': ipv4,
        if (ipv6 != null) 'ipv6': ipv6,
        if (cname != null) 'cname': cname,
        if (txt != null) 'txt': txt,
        if (metadata != null) 'metadata': metadata,
      };
}

/// Domain availability
class DomainAvailability {
  final String name;
  final bool available;
  final double? price;
  final bool premium;

  const DomainAvailability({
    required this.name,
    required this.available,
    this.price,
    this.premium = false,
  });

  factory DomainAvailability.fromJson(Map<String, dynamic> json) => DomainAvailability(
        name: json['name'] as String,
        available: json['available'] as bool,
        price: (json['price'] as num?)?.toDouble(),
        premium: json['premium'] as bool? ?? false,
      );
}

/// Options for registering a domain
class RegisterDomainOptions {
  final int? years;
  final bool? autoRenew;

  const RegisterDomainOptions({this.years, this.autoRenew});

  Map<String, dynamic> toJson() => {
        if (years != null) 'years': years,
        if (autoRenew != null) 'autoRenew': autoRenew,
      };
}

// ==================== DNS Types ====================

/// DNS record type
enum DnsRecordType { A, AAAA, CNAME, TXT, MX, NS, SRV, CAA }

/// DNS record
class DnsRecord {
  final DnsRecordType type;
  final String name;
  final String value;
  final int ttl;
  final int? priority;

  const DnsRecord({
    required this.type,
    required this.name,
    required this.value,
    this.ttl = 3600,
    this.priority,
  });

  factory DnsRecord.fromJson(Map<String, dynamic> json) => DnsRecord(
        type: DnsRecordType.values.firstWhere((e) => e.name == json['type']),
        name: json['name'] as String,
        value: json['value'] as String,
        ttl: json['ttl'] as int? ?? 3600,
        priority: json['priority'] as int?,
      );

  Map<String, dynamic> toJson() => {
        'type': type.name,
        'name': name,
        'value': value,
        'ttl': ttl,
        if (priority != null) 'priority': priority,
      };
}

/// DNS zone
class DnsZone {
  final String domain;
  final List<DnsRecord> records;
  final DateTime updatedAt;

  const DnsZone({
    required this.domain,
    required this.records,
    required this.updatedAt,
  });

  factory DnsZone.fromJson(Map<String, dynamic> json) => DnsZone(
        domain: json['domain'] as String,
        records: (json['records'] as List).map((e) => DnsRecord.fromJson(e)).toList(),
        updatedAt: DateTime.fromMillisecondsSinceEpoch(json['updatedAt'] as int),
      );
}

// ==================== Deployment Types ====================

/// Deployment status
enum DeploymentStatus { pending, building, deploying, active, failed, inactive }

/// Deployment information
class Deployment {
  final String id;
  final String domain;
  final String cid;
  final DeploymentStatus status;
  final String url;
  final DateTime createdAt;
  final DateTime updatedAt;
  final String? buildLogs;
  final String? errorMessage;

  const Deployment({
    required this.id,
    required this.domain,
    required this.cid,
    required this.status,
    required this.url,
    required this.createdAt,
    required this.updatedAt,
    this.buildLogs,
    this.errorMessage,
  });

  factory Deployment.fromJson(Map<String, dynamic> json) => Deployment(
        id: json['id'] as String,
        domain: json['domain'] as String,
        cid: json['cid'] as String,
        status: DeploymentStatus.values.firstWhere(
            (e) => e.name == json['status'],
            orElse: () => DeploymentStatus.pending),
        url: json['url'] as String,
        createdAt: DateTime.fromMillisecondsSinceEpoch(json['createdAt'] as int),
        updatedAt: DateTime.fromMillisecondsSinceEpoch(json['updatedAt'] as int),
        buildLogs: json['buildLogs'] as String?,
        errorMessage: json['errorMessage'] as String?,
      );
}

/// Deploy options
class DeployOptions {
  final String? domain;
  final String? subdomain;
  final bool? spa;
  final bool? cleanUrls;
  final bool? trailingSlash;

  const DeployOptions({
    this.domain,
    this.subdomain,
    this.spa,
    this.cleanUrls,
    this.trailingSlash,
  });

  Map<String, dynamic> toJson() => {
        if (domain != null) 'domain': domain,
        if (subdomain != null) 'subdomain': subdomain,
        if (spa != null) 'spa': spa,
        if (cleanUrls != null) 'cleanUrls': cleanUrls,
        if (trailingSlash != null) 'trailingSlash': trailingSlash,
      };
}

// ==================== SSL Types ====================

/// Certificate status
enum CertificateStatus { pending, issued, expired, revoked }

/// SSL certificate
class Certificate {
  final String domain;
  final CertificateStatus status;
  final bool autoRenew;
  final String issuer;
  final DateTime? issuedAt;
  final DateTime? expiresAt;
  final String? fingerprint;

  const Certificate({
    required this.domain,
    required this.status,
    required this.autoRenew,
    required this.issuer,
    this.issuedAt,
    this.expiresAt,
    this.fingerprint,
  });

  factory Certificate.fromJson(Map<String, dynamic> json) => Certificate(
        domain: json['domain'] as String,
        status: CertificateStatus.values.firstWhere(
            (e) => e.name == json['status'],
            orElse: () => CertificateStatus.pending),
        autoRenew: json['autoRenew'] as bool? ?? false,
        issuer: json['issuer'] as String,
        issuedAt: json['issuedAt'] != null
            ? DateTime.fromMillisecondsSinceEpoch(json['issuedAt'] as int)
            : null,
        expiresAt: json['expiresAt'] != null
            ? DateTime.fromMillisecondsSinceEpoch(json['expiresAt'] as int)
            : null,
        fingerprint: json['fingerprint'] as String?,
      );
}

/// Provision SSL options
class ProvisionSslOptions {
  final bool? includeWww;
  final bool? autoRenew;

  const ProvisionSslOptions({this.includeWww, this.autoRenew});

  Map<String, dynamic> toJson() => {
        if (includeWww != null) 'includeWww': includeWww,
        if (autoRenew != null) 'autoRenew': autoRenew,
      };
}

// ==================== Analytics Types ====================

/// Analytics data
class AnalyticsData {
  final String domain;
  final String period;
  final int pageViews;
  final int uniqueVisitors;
  final int bandwidth;
  final List<PageView> topPages;
  final List<Referrer> topReferrers;
  final List<Country> topCountries;

  const AnalyticsData({
    required this.domain,
    required this.period,
    required this.pageViews,
    required this.uniqueVisitors,
    required this.bandwidth,
    required this.topPages,
    required this.topReferrers,
    required this.topCountries,
  });

  factory AnalyticsData.fromJson(Map<String, dynamic> json) => AnalyticsData(
        domain: json['domain'] as String,
        period: json['period'] as String,
        pageViews: json['pageViews'] as int,
        uniqueVisitors: json['uniqueVisitors'] as int,
        bandwidth: json['bandwidth'] as int,
        topPages: (json['topPages'] as List).map((e) => PageView.fromJson(e)).toList(),
        topReferrers: (json['topReferrers'] as List).map((e) => Referrer.fromJson(e)).toList(),
        topCountries: (json['topCountries'] as List).map((e) => Country.fromJson(e)).toList(),
      );
}

class PageView {
  final String path;
  final int views;
  const PageView({required this.path, required this.views});
  factory PageView.fromJson(Map<String, dynamic> json) =>
      PageView(path: json['path'] as String, views: json['views'] as int);
}

class Referrer {
  final String referrer;
  final int count;
  const Referrer({required this.referrer, required this.count});
  factory Referrer.fromJson(Map<String, dynamic> json) =>
      Referrer(referrer: json['referrer'] as String, count: json['count'] as int);
}

class Country {
  final String country;
  final int count;
  const Country({required this.country, required this.count});
  factory Country.fromJson(Map<String, dynamic> json) =>
      Country(country: json['country'] as String, count: json['count'] as int);
}

/// Analytics options
class AnalyticsOptions {
  final String? period;
  final String? start;
  final String? end;

  const AnalyticsOptions({this.period, this.start, this.end});
}

// ==================== Error Types ====================

/// Hosting error
class HostingException implements Exception {
  final String message;
  final String? code;
  final int? statusCode;

  const HostingException(this.message, {this.code, this.statusCode});

  @override
  String toString() => 'HostingException: $message';
}
