import Foundation
import SwiftUI

// MARK: - View State

/// Represents the state of async data loading in a view
enum ViewState<T> {
    case idle
    case loading
    case loaded(T)
    case error(String)

    var isIdle: Bool {
        if case .idle = self { return true }
        return false
    }

    var isLoading: Bool {
        if case .loading = self { return true }
        return false
    }

    var isLoaded: Bool {
        if case .loaded = self { return true }
        return false
    }

    var isError: Bool {
        if case .error = self { return true }
        return false
    }

    var data: T? {
        if case .loaded(let data) = self { return data }
        return nil
    }

    var errorMessage: String? {
        if case .error(let message) = self { return message }
        return nil
    }

    /// Map the loaded data to a new type
    func map<U>(_ transform: (T) -> U) -> ViewState<U> {
        switch self {
        case .idle:
            return .idle
        case .loading:
            return .loading
        case .loaded(let data):
            return .loaded(transform(data))
        case .error(let message):
            return .error(message)
        }
    }
}

// MARK: - Form Field

/// Container for form field state with validation support
struct FormField<T> {
    var value: T
    var error: String?
    var isDirty: Bool = false

    /// Validate the field using the provided validator
    mutating func validate(_ validator: (T) -> ValidationError?) {
        if let validationError = validator(value) {
            error = validationError.errorDescription
        } else {
            error = nil
        }
    }

    /// Mark the field as having been interacted with
    mutating func touch() {
        isDirty = true
    }

    /// Clear any error
    mutating func clearError() {
        error = nil
    }

    /// Check if field has no error. Note: returns true for fields that have
    /// never been validated — use `isValidated` to confirm validation has run.
    var isValid: Bool {
        error == nil
    }

    /// True only after `validate()` has been called and produced no error
    var isValidated: Bool {
        isDirty && error == nil
    }

    /// Check if field should show error (dirty and has error)
    var shouldShowError: Bool {
        isDirty && error != nil
    }
}

// MARK: - String Form Field

extension FormField where T == String {
    /// Initialize an empty string form field
    init() {
        self.value = ""
        self.error = nil
        self.isDirty = false
    }

    /// Initialize with a default value
    init(initialValue: String) {
        self.value = initialValue
        self.error = nil
        self.isDirty = false
    }

    /// Check if the field is empty
    var isEmpty: Bool {
        value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
    }

    /// Get trimmed value
    var trimmedValue: String {
        value.trimmingCharacters(in: .whitespacesAndNewlines)
    }
}

// MARK: - Optional Form Field

extension FormField where T == String? {
    /// Initialize an empty optional string form field
    init() {
        self.value = nil
        self.error = nil
        self.isDirty = false
    }
}

// MARK: - Binding Extensions

extension FormField {
    /// Create a binding for the value
    func binding(onChange: @escaping (T) -> Void) -> Binding<T> {
        Binding(
            get: { self.value },
            set: { onChange($0) }
        )
    }
}

// MARK: - Form State Protocol

/// Protocol for form state containers
protocol FormState {
    /// Validate all fields in the form
    mutating func validateAll()

    /// Check if the entire form is valid
    var isValid: Bool { get }

    /// Reset the form to initial state
    mutating func reset()
}
