//
// Copyright © 2023 Nevis Security AG. All rights reserved.
//

import NevisMobileAuthentication

struct TypedSessionProvider: Codable {
	// MARK: Properties

	let wrapped: SessionProvider

	// MARK: Initialization

	init(wrapped: SessionProvider) {
		self.wrapped = wrapped
	}

	// MARK: Coding Keys

	enum SessionProviderType: String, Encodable {
		case cookie = "CookieSessionProvider"
		case jwt = "JwtSessionProvider"
	}

	enum CodingKeys: String, CodingKey {
		case cookies
		case jwt
	}

	// MARK: Decodable

	init(from decoder: Decoder) throws {
		let container = try decoder.container(keyedBy: TypedCodingKeys.self)
		let type = try container.decode(String.self, forKey: .type)
		switch type {
			case SessionProviderType.cookie.rawValue:
				self.wrapped = try container.decode(CookieSessionProvider.self, forKey: .data)
			case SessionProviderType.jwt.rawValue:
				self.wrapped = try container.decode(JwtSessionProvider.self, forKey: .data)
			default:
				throw DecodingError.dataCorrupted(
					DecodingError.Context(
						codingPath: container.codingPath,
						debugDescription: "Failed to decode session provider!"
					)
				)
		}
	}

	// MARK: Encodable

	func encode(to encoder: Encoder) throws {
		var container = encoder.container(keyedBy: TypedCodingKeys.self)
		switch wrapped {
			case is CookieSessionProvider:
				try container.encode(SessionProviderType.cookie, forKey: .type)
			case is JwtSessionProvider:
				try container.encode(SessionProviderType.jwt, forKey: .type)
			default:
				throw EncodingError.invalidValue(
					wrapped,
					EncodingError.Context(
						codingPath: container.codingPath,
						debugDescription: "Failed to encode session provider!"
					)
				)
		}

		try wrapped.encode(to: container.superEncoder(forKey: .data))
	}
}
