// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package xyz.apiote.bimba.czwek.units

import android.content.Context
import android.icu.util.LocaleData
import android.icu.util.LocaleData.MeasurementSystem
import android.icu.util.ULocale
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.preference.PreferenceManager
import java.util.Locale

abstract class UnitSystem(val base: Int) {
	companion object {
		@RequiresApi(Build.VERSION_CODES.P)
		private fun forMeasureSystem(ms: MeasurementSystem) =
			when (ms) {
				MeasurementSystem.SI -> {
					Metric
				}

				MeasurementSystem.UK -> {
					Imperial
				}

				MeasurementSystem.US -> {
					USCustomary
				}

				else -> {
					Metric
				}
			}

		private fun forLocale(country: String): UnitSystem = if (setOf(
				"AG", "BS", "BZ", "DM", "GD", "MH", "FM", "PW", "KN", "LC", "VC", "GB", "AI", "VG",
				"IO", "KY", "FK", "MS", "SH", "TC", "GG", "IM", "JE", "US", "AS", "GU", "MP", "PR", "VI"
			).contains(country)
		) {
			Imperial
		} else {
			Metric
		}

		private fun getDefault() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
			forMeasureSystem(LocaleData.getMeasurementSystem(ULocale.forLocale(Locale.getDefault())))
		} else {
			forLocale(Locale.getDefault().country)
		}

		fun getSelected(context: Context): UnitSystem =
			when (PreferenceManager.getDefaultSharedPreferences(context)
				.getString("unit_system", "default")) {
				"default" -> getDefault()
				"metric" -> Metric
				"imperial" -> Imperial
				"customary" -> USCustomary
				"tgm10" -> TGM(10)
				"tgm12" -> TGM(12)
				else -> getDefault()
			}
	}

	abstract fun timeUnit(count: Long): TimeUnit
	abstract fun timeUnit(other: TimeUnit): TimeUnit
	abstract fun speedUnit(count: Double): SpeedUnit
	abstract fun speedUnit(other: SpeedUnit): SpeedUnit
	abstract fun distanceUnit(count: Double): DistanceUnit
	abstract fun distanceUnit(other: DistanceUnit): DistanceUnit

	abstract fun toString(context: Context, s: SpeedUnit): String
	abstract fun toString(context: Context, t: TimeUnit): String
	abstract fun toString(context: Context, d: DistanceUnit): String
}

interface TimeUnit {
	fun milliseconds(): Long
	fun toString(context: Context, base: Int): String
	fun contentDescription(context: Context, base: Int): String
}

interface SpeedUnit {
	fun mps(): Double
	fun toString(context: Context, base: Int): String
	fun contentDescription(context: Context, base: Int): String
}

interface DistanceUnit {
	fun meters(): Double
	fun toString(context: Context, base: Int): String
	fun contentDescription(context: Context, base: Int): String
}
