import Combine
import Foundation

@MainActor
final class LocalizationStore: ObservableObject {
    @Published private(set) var localeCode: String

    private let bundle: Bundle

    private static let supportedLocaleCodes = ["en", "sv"]
    private static let fallbackLocaleCode = "en"

    init(bundle: Bundle? = nil, localeCode: String = Locale.preferredLanguages.first.map { String($0.prefix(2)) } ?? "en") {
        self.bundle = bundle ?? Self.defaultBundle
        self.localeCode = Self.normalize(localeCode)
    }

    func setLocale(_ localeCode: String) {
        self.localeCode = Self.normalize(localeCode)
    }

    func string(for key: String) -> String {
        string(for: key, localeCode: localeCode)
    }

    func string(for key: String, localeCode: String) -> String {
        guard let localizedBundle = localizedBundle(for: localeCode) else {
            return fallbackString(for: key, localeCode: localeCode)
        }

        let value = localizedBundle.localizedString(forKey: key, value: nil, table: nil)
        if value == key {
            return fallbackString(for: key, localeCode: localeCode)
        }

        return value
    }

    func localeName(for targetLocaleCode: String, displayLocaleCode: String? = nil) -> String {
        let key = Self.normalize(targetLocaleCode) == "sv" ? "locale_swedish" : "locale_english"
        return string(for: key, localeCode: displayLocaleCode ?? localeCode)
    }

    private func fallbackString(for key: String, localeCode: String) -> String {
        guard localeCode != Self.fallbackLocaleCode else {
            return key
        }

        return string(for: key, localeCode: Self.fallbackLocaleCode)
    }

    private func localizedBundle(for localeCode: String) -> Bundle? {
        guard let path = bundle.path(forResource: localeCode, ofType: "lproj") else {
            return nil
        }

        return Bundle(path: path)
    }

    private static func normalize(_ localeCode: String) -> String {
        guard supportedLocaleCodes.contains(localeCode) else {
            return fallbackLocaleCode
        }

        return localeCode
    }

    private static var defaultBundle: Bundle {
        #if SWIFT_PACKAGE
        .module
        #else
        .main
        #endif
    }
}
