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

package xyz.apiote.bimba.czwek.repo

import android.content.Context
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.api.CongestionLevelV1
import xyz.apiote.bimba.czwek.api.OccupancyStatusV1
import xyz.apiote.bimba.czwek.api.VehicleV1
import xyz.apiote.bimba.czwek.api.VehicleV2
import xyz.apiote.bimba.czwek.api.VehicleV3
import xyz.apiote.bimba.czwek.units.Mps

enum class CongestionLevel {
	UNKNOWN, SMOOTH, STOP_AND_GO, SIGNIFICANT, SEVERE;

	fun toString(context: Context): String {
		return when (this) {
			UNKNOWN -> context.getString(R.string.congestion_unknown)
			SMOOTH -> context.getString(R.string.congestion_smooth)
			STOP_AND_GO -> context.getString(R.string.congestion_stop_and_go)
			SIGNIFICANT -> context.getString(R.string.congestion_congestion)
			SEVERE -> context.getString(R.string.congestion_jams)
		}
	}

	companion object {
		fun of(type: CongestionLevelV1): CongestionLevel {
			return when (type) {
				CongestionLevelV1.UNKNOWN -> valueOf("UNKNOWN")
				CongestionLevelV1.SMOOTH -> valueOf("SMOOTH")
				CongestionLevelV1.STOP_AND_GO -> valueOf("STOP_AND_GO")
				CongestionLevelV1.SIGNIFICANT -> valueOf("SIGNIFICANT")
				CongestionLevelV1.SEVERE -> valueOf("SEVERE")
			}
		}
	}
}

enum class OccupancyStatus {
	UNKNOWN, EMPTY, MANY_AVAILABLE, FEW_AVAILABLE, STANDING_ONLY, CRUSHED, FULL, NOT_ACCEPTING;

	fun toString(context: Context):String {
		return when (this) {
			UNKNOWN -> context.getString(R.string.occupancy_unknown)
			EMPTY -> context.getString(R.string.occupancy_empty)
			MANY_AVAILABLE -> context.getString(R.string.occupancy_many_seats)
			FEW_AVAILABLE -> context.getString(R.string.occupancy_few_seats)
			STANDING_ONLY -> context.getString(R.string.occupancy_standing_only)
			CRUSHED -> context.getString(R.string.occupancy_crowded)
			FULL -> context.getString(R.string.occupancy_full)
			NOT_ACCEPTING -> context.getString(R.string.occupancy_wont_let)
		}
	}
	companion object {
		fun of(type: OccupancyStatusV1): OccupancyStatus {
			return when (type) {
				OccupancyStatusV1.UNKNOWN -> valueOf("UNKNOWN")
				OccupancyStatusV1.EMPTY -> valueOf("EMPTY")
				OccupancyStatusV1.MANY_AVAILABLE -> valueOf("MANY_AVAILABLE")
				OccupancyStatusV1.FEW_AVAILABLE -> valueOf("FEW_AVAILABLE")
				OccupancyStatusV1.STANDING_ONLY -> valueOf("STANDING_ONLY")
				OccupancyStatusV1.CRUSHED -> valueOf("CRUSHED")
				OccupancyStatusV1.FULL -> valueOf("FULL")
				OccupancyStatusV1.NOT_ACCEPTING -> valueOf("NOT_ACCEPTING")
			}
		}
	}
}

data class Vehicle(
	val ID: String,
	val Position: Position,
	val Capabilities: UShort,
	val Speed: Mps,
	val Line: LineStub,
	val Headsign: String,
	val congestionLevel: CongestionLevel,
	val occupancyStatus: OccupancyStatus
) : Locatable {
	constructor(v: VehicleV1) : this(
		v.ID,
		Position(v.Position),
		v.Capabilities,
		Mps(v.Speed.toDouble()),
		LineStub(v.Line),
		v.Headsign,
		CongestionLevel.of(v.CongestionLevel),
		OccupancyStatus.of(v.OccupancyStatus)
	)

	constructor(v: VehicleV2) : this(
		v.ID,
		Position(v.Position),
		v.Capabilities,
		Mps(v.Speed.toDouble()),
		LineStub(v.Line),
		v.Headsign,
		CongestionLevel.of(v.CongestionLevel),
		OccupancyStatus.of(v.OccupancyStatus)
	)

	constructor(v: VehicleV3) : this(
		v.ID,
		Position(v.Position),
		v.Capabilities,
		Mps(v.Speed.toDouble()),
		LineStub(v.Line),
		v.Headsign,
		CongestionLevel.of(v.CongestionLevel),
		OccupancyStatus.of(v.OccupancyStatus)
	)

	enum class Capability(val bit: UShort) {
		RAMP(0b0001u), LOW_FLOOR(0b0010u), LOW_ENTRY(0b0001_0000_0000u), AC(0b0100u), BIKE(0b1000u), VOICE(
			0b0001_0000u
		),
		TICKET_MACHINE(0b0010_0000u), TICKET_DRIVER(0b0100_0000u), USB_CHARGING(0b1000_0000u)
	}

	override fun icon(context: Context, scale: Float) = Line.icon(context, scale)

	override fun location(): Position = Position

	override fun id(): String = ID

	fun congestion(context: Context) = congestionLevel.toString(context)

	fun occupancy(context: Context)= occupancyStatus.toString(context)

	fun getCapability(field: Capability): Boolean {
		return Capabilities.and(field.bit) != (0).toUShort()
	}
}