import Foundation

enum LiveActivitySnapshotBuilder {
    static func makeContentState(
        person: Person,
        player: Player,
        isRunning: Bool,
        now: Date = Date()
    ) -> CharacterLiveActivityAttributes.ContentState {
        CharacterLiveActivityAttributes.ContentState(
            gameDate: player.date,
            gameTime: formatGameTime(hour: player.hourOfDay, minute: player.minuteOfHour),
            age: max(0, person.ageYears),
            season: player.season,
            location: clean(person.location, fallback: "Life in progress"),
            statusMessage: clean(person.intraDayMessage, fallback: statusMessage(for: player.status)),
            energy: clamp(person.calcEnergy, min: 0, max: 999),
            health: clamp(person.health, min: 0, max: 100),
            happiness: clamp(person.happiness, min: 0, max: 100),
            speedLabel: speedLabel(for: player.gameSpeed),
            isRunning: isRunning,
            updatedAt: isoTimestamp(from: now)
        )
    }

    static func avatarCacheKey(for person: Person) -> String {
        let source = person.id.isEmpty ? person.fullName : person.id
        let safeKey = source
            .lowercased()
            .map { character -> Character in
                if character.isLetter || character.isNumber {
                    return character
                }
                return "-"
            }

        let collapsed = String(safeKey).trimmingCharacters(in: CharacterSet(charactersIn: "-"))
        return "character-avatar-\(collapsed.isEmpty ? "current" : collapsed)"
    }

    static func characterName(for person: Person) -> String {
        let fullName = person.fullName.trimmingCharacters(in: .whitespacesAndNewlines)
        if !fullName.isEmpty {
            return fullName
        }
        return "Your character"
    }

    static func isMajorVisibleChange(
        from previous: CharacterLiveActivityAttributes.ContentState?,
        to next: CharacterLiveActivityAttributes.ContentState
    ) -> Bool {
        guard let previous else { return true }

        return previous.statusMessage != next.statusMessage
            || previous.location != next.location
            || previous.isRunning != next.isRunning
            || previous.health != next.health
            || previous.energy != next.energy
            || previous.happiness != next.happiness
            || previous.speedLabel != next.speedLabel
    }

    private static func formatGameTime(hour: Int, minute: Int) -> String {
        let safeHour = max(0, min(23, hour))
        let safeMinute = max(0, min(59, minute))
        let period = safeHour >= 12 ? "PM" : "AM"
        let displayHour = safeHour % 12 == 0 ? 12 : safeHour % 12
        return "\(displayHour):\(String(format: "%02d", safeMinute)) \(period)"
    }

    private static func speedLabel(for speed: Int) -> String {
        switch speed {
        case Constants.GameSpeed.slowest:
            return "Slowest"
        case Constants.GameSpeed.slow:
            return "Slow"
        case Constants.GameSpeed.normal:
            return "Normal"
        case Constants.GameSpeed.fast:
            return "Fast"
        case Constants.GameSpeed.fastest:
            return "Fastest"
        case Constants.GameSpeed.instant:
            return "Instant"
        case 0:
            return "Paused"
        default:
            return "\(speed)"
        }
    }

    private static func statusMessage(for status: String) -> String {
        switch status {
        case "playing":
            return "Living life"
        case "creating":
            return "Creating character"
        default:
            return status.isEmpty ? "Life in progress" : status
        }
    }

    private static func clean(_ value: String, fallback: String) -> String {
        let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
        return trimmed.isEmpty ? fallback : trimmed
    }

    private static func clamp(_ value: Int, min: Int, max: Int) -> Int {
        Swift.max(min, Swift.min(max, value))
    }

    private static func isoTimestamp(from date: Date) -> String {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime]
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        return formatter.string(from: date)
    }
}

enum LiveActivityUpdateThrottle {
    static let minimumUpdateInterval: TimeInterval = 15

    static func shouldUpdate(
        lastUpdate: Date?,
        now: Date = Date(),
        majorChange: Bool
    ) -> Bool {
        if majorChange {
            return true
        }

        guard let lastUpdate else {
            return true
        }

        return now.timeIntervalSince(lastUpdate) >= minimumUpdateInterval
    }
}

enum LiveActivityPromptPolicy {
    static func shouldShowPrompt(
        promptAsked: Bool,
        isAvailable: Bool,
        isPlayable: Bool
    ) -> Bool {
        !promptAsked && isAvailable && isPlayable
    }

    static func isPlayable(person: Person, player: Player) -> Bool {
        !person.id.isEmpty
            && !person.firstname.isEmpty
            && person.status != "dead"
            && player.status != "creating"
    }
}
