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

package xyz.apiote.bimba.czwek.units

import android.content.Context
import xyz.apiote.bimba.czwek.R
import java.text.NumberFormat

object Metric : UnitSystem(10) {

	override fun timeUnit(count: Long): TimeUnit = Second(count.toDouble())
	override fun timeUnit(other: TimeUnit): TimeUnit = Second(other)

	override fun speedUnit(count: Double): SpeedUnit = Kmph(count)
	override fun speedUnit(other: SpeedUnit): SpeedUnit = Kmph(other)

	override fun distanceUnit(count: Double): DistanceUnit = Km(count)
	override fun distanceUnit(other: DistanceUnit): DistanceUnit = Km(other)

	override fun toString(context: Context, s: SpeedUnit): String = s.toString(context, base)
	override fun toString(context: Context, t: TimeUnit): String = t.toString(context, base)
	override fun toString(context: Context, d: DistanceUnit): String = d.toString(context, base)
}

class Km(val km: Double) : DistanceUnit {
	constructor(other: DistanceUnit) : this(other.meters() / 1000)

	override fun meters(): Double = km * 1000
	override fun toString(context: Context, base: Int): String =
		if (km < 1) {
			context.getString(
				R.string.distance_in_m,
				NumberFormat.getIntegerInstance().format((km * 1000).toInt())
			)
		} else {
			context.getString(
				R.string.distance_in_km,
				NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(km)
			)
		}

	override fun contentDescription(context: Context, base: Int): String =
		if (km < 1) {
			context.resources.getQuantityString(R.plurals.distance_in_m_cd, (km * 1000).toInt())
		} else {
			val kilometres = km.toInt()
			val metres = ((km - kilometres) * 1000).toInt()
			val kmString = context.resources.getQuantityString(R.plurals.distance_in_km_cd, kilometres)
			val mString = context.resources.getQuantityString(R.plurals.distance_in_m_cd, metres)
			if (metres > 0) {
				context.getString(R.string.distance_in_two_units_cd, kmString, mString)
			} else {
				kmString
			}
		}
}

class Metre(val m: Double) : DistanceUnit {
	override fun meters(): Double = m

	override fun toString(context: Context, base: Int): String =
		context.getString(R.string.distance_in_m, NumberFormat.getIntegerInstance().format(m.toInt()))

	override fun contentDescription(context: Context, base: Int): String =
		context.resources.getQuantityString(R.plurals.distance_in_m_cd, m.toInt(), m.toInt())
}

class Second(val seconds: Double) : TimeUnit {
	constructor(s: Int) : this(s.toDouble())
	constructor(other: TimeUnit) : this((other.milliseconds().toDouble() / 1000))

	override fun milliseconds(): Long = (seconds * 1000).toLong()
	override fun toString(context: Context, base: Int): String =
		context.getString(
			R.string.time_in_s,
			NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(seconds)
		)

	override fun contentDescription(context: Context, base: Int): String =
		context.resources.getQuantityString(R.plurals.time_in_s_cd, seconds.toInt(), seconds)
}

class Mps(val mps: Double) : SpeedUnit {
	constructor(s: Int) : this(s.toDouble())
	constructor(other: SpeedUnit) : this(other.mps())

	override fun mps(): Double = mps
	override fun toString(context: Context, base: Int): String =
		context.getString(
			R.string.speed_in_m_per_s,
			NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(mps)
		)

	override fun contentDescription(context: Context, base: Int): String =
		context.resources.getQuantityString(R.plurals.speed_in_m_per_s_cd, mps.toInt(), mps)
}

class Kmph(val kmph: Double) : SpeedUnit {
	constructor(s: Int) : this(s.toDouble())
	constructor(other: SpeedUnit) : this(other.mps() * 3.6)

	override fun mps(): Double = kmph / 3.6
	override fun toString(context: Context, base: Int): String =
		context.getString(
			R.string.speed_in_km_per_h,
			NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(kmph)
		)

	override fun contentDescription(context: Context, base: Int): String =
		context.resources.getQuantityString(R.plurals.speed_in_km_per_h_cd, kmph.toInt(), kmph.toInt())
}