import Foundation

// MARK: - Enums

/// Status of a pinned item.
public enum PinStatus: String, Codable {
    case queued
    case pinning
    case pinned
    case failed
    case unpinned
}

/// Hash algorithm for content addressing.
public enum HashAlgorithm: String, Codable {
    case sha2_256 = "sha2-256"
    case blake3
}

/// Type of directory entry.
public enum EntryType: String, Codable {
    case file
    case directory
}

// MARK: - Configuration

/// Configuration for the storage client.
public struct StorageConfig {
    public let apiKey: String
    public let endpoint: String
    public let gateway: String
    public let timeout: TimeInterval
    public let retries: Int
    public let debug: Bool

    public init(
        apiKey: String,
        endpoint: String = "https://storage.synor.io/v1",
        gateway: String = "https://gateway.synor.io",
        timeout: TimeInterval = 60.0,
        retries: Int = 3,
        debug: Bool = false
    ) {
        self.apiKey = apiKey
        self.endpoint = endpoint
        self.gateway = gateway
        self.timeout = timeout
        self.retries = retries
        self.debug = debug
    }
}

// MARK: - Upload Models

/// Options for file upload.
public struct UploadOptions {
    public let name: String?
    public let wrapWithDirectory: Bool
    public let hashAlgorithm: HashAlgorithm
    public let chunkSize: Int?
    public let pinDurationDays: Int?

    public init(
        name: String? = nil,
        wrapWithDirectory: Bool = false,
        hashAlgorithm: HashAlgorithm = .sha2_256,
        chunkSize: Int? = nil,
        pinDurationDays: Int? = nil
    ) {
        self.name = name
        self.wrapWithDirectory = wrapWithDirectory
        self.hashAlgorithm = hashAlgorithm
        self.chunkSize = chunkSize
        self.pinDurationDays = pinDurationDays
    }
}

/// Response from upload operation.
public struct UploadResponse: Codable {
    public let cid: String
    public let size: Int64
    public let name: String?
    public let createdAt: String

    enum CodingKeys: String, CodingKey {
        case cid, size, name
        case createdAt = "created_at"
    }
}

// MARK: - Pin Models

/// Pin information.
public struct Pin: Codable {
    public let cid: String
    public let name: String?
    public let status: PinStatus
    public let size: Int64
    public let createdAt: String
    public let expiresAt: String?
    public let delegates: [String]?

    enum CodingKeys: String, CodingKey {
        case cid, name, status, size, delegates
        case createdAt = "created_at"
        case expiresAt = "expires_at"
    }
}

/// Request to pin content.
public struct PinRequest: Codable {
    public let cid: String
    public let name: String?
    public let durationDays: Int?
    public let origins: [String]?
    public let meta: [String: String]?

    public init(
        cid: String,
        name: String? = nil,
        durationDays: Int? = nil,
        origins: [String]? = nil,
        meta: [String: String]? = nil
    ) {
        self.cid = cid
        self.name = name
        self.durationDays = durationDays
        self.origins = origins
        self.meta = meta
    }

    enum CodingKeys: String, CodingKey {
        case cid, name, origins, meta
        case durationDays = "duration_days"
    }
}

// MARK: - CAR Models

/// CAR (Content Addressable Archive) file.
public struct CarFile: Codable {
    public let cid: String
    public let size: Int64
    public let roots: [String]
    public let createdAt: String

    enum CodingKeys: String, CodingKey {
        case cid, size, roots
        case createdAt = "created_at"
    }
}

/// Entry in a CAR file for creation.
public struct CarEntry {
    public let path: String
    public let content: Data

    public init(path: String, content: Data) {
        self.path = path
        self.content = content
    }
}

// MARK: - Directory Models

/// Directory entry.
public struct DirectoryEntry: Codable {
    public let name: String
    public let cid: String
    public let size: Int64
    public let type: EntryType
}

/// File entry for directory creation.
public struct FileEntry {
    public let path: String
    public let content: Data

    public init(path: String, content: Data) {
        self.path = path
        self.content = content
    }
}

// MARK: - Statistics

/// Storage usage statistics.
public struct StorageStats: Codable {
    public let totalSize: Int64
    public let pinCount: Int
    public let bandwidthUsed: Int64
    public let quotaUsed: Double

    enum CodingKeys: String, CodingKey {
        case totalSize = "total_size"
        case pinCount = "pin_count"
        case bandwidthUsed = "bandwidth_used"
        case quotaUsed = "quota_used"
    }
}

// MARK: - Internal Types

struct ImportCarResponse: Codable {
    let cids: [String]
}

// MARK: - Errors

/// Errors thrown by storage operations.
public enum StorageError: Error, LocalizedError {
    case invalidResponse
    case httpError(statusCode: Int, message: String)
    case networkError(Error)
    case encodingError(Error)
    case decodingError(Error)
    case uploadFailed(String)

    public var errorDescription: String? {
        switch self {
        case .invalidResponse:
            return "Invalid response from server"
        case .httpError(let code, let message):
            return "HTTP error \(code): \(message)"
        case .networkError(let error):
            return "Network error: \(error.localizedDescription)"
        case .encodingError(let error):
            return "Encoding error: \(error.localizedDescription)"
        case .decodingError(let error):
            return "Decoding error: \(error.localizedDescription)"
        case .uploadFailed(let reason):
            return "Upload failed: \(reason)"
        }
    }
}
