package com.vnidrop.app.core

import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import uniffi.vnidrop.ReceiveOutputSink
import uniffi.vnidrop.ReceiveOutputSinkV2

data class CoreStatus(
	val endpointId: String,
	val activeTransfers: ULong,
	val activeShares: ULong,
)

data class CoreEventModel(
	val id: String,
	val revision: ULong,
	val timestamp: Long,
	val scope: String,
	val transferId: ULong?,
	val direction: String?,
	val phase: String,
	val kind: String,
	val dataJson: String,
)

enum class ShareAccessPolicy {
	RequireApproval,
	AnyoneWithTransfer,
}

enum class RelayMode {
	Automatic,
	StrictCustom,
	CustomWithDirectFallback,
	LocalOnly,
}

data class RelaySettings(
	val mode: RelayMode = RelayMode.Automatic,
	val relayUrls: List<String> = emptyList(),
)

val RelayMode.usesCustomRelayUrls: Boolean
	get() = this == RelayMode.StrictCustom || this == RelayMode.CustomWithDirectFallback

enum class TransferDirection {
	Send,
	Receive,
}

enum class TransferStatus {
	Importing,
	Sharing,
	Receiving,
	Done,
	Failed,
	Cancelled,
	Stopped,
}

data class Transfer(
	val localId: String,
	val transferId: ULong,
	val direction: TransferDirection,
	val status: TransferStatus,
	val peerId: String?,
	val transferName: String?,
	val contentHash: String?,
	val fileCount: ULong,
	val totalSize: ULong,
	val ticket: String?,
	val accessPolicy: ShareAccessPolicy,
	val createdAt: Long,
	val updatedAt: Long,
)

data class Share(
	val transferId: ULong,
	val ticket: String,
	val transferName: String,
	val contentHash: String,
	val fileCount: ULong,
	val totalSize: ULong,
)

data class TransferMetadataModel(
	val transferId: ULong,
	val transferName: String,
	val senderName: String?,
	val contentHash: String,
	val fileCount: ULong,
	val totalSize: ULong,
)

data class TicketInspectionModel(
	val kind: String,
	val metadata: TransferMetadataModel,
)

data class ReceiverRequestModel(
	val id: String,
	val transferId: ULong,
	val remoteEndpointId: String,
	val transferName: String,
	val receiverName: String?,
	val receiverDeviceName: String?,
	val appVersion: String,
	val status: ReceiverDeliveryStatus,
	val reason: String?,
	val requestedAt: Long,
	val respondedAt: Long?,
	val completedAt: Long?,
)

enum class ReceiverDeliveryStatus {
	Requested,
	Accepted,
	Refused,
	Expired,
	Completed,
	Failed,
	Unknown,
}

data class CoreState(
	val isInitialized: Boolean = false,
	val status: CoreStatus? = null,
	val events: List<CoreEventModel> = emptyList(),
	val transfers: List<Transfer> = emptyList(),
	val lastShare: Share? = null,
	val lastInspection: TicketInspectionModel? = null,
)

data class CoreStorageUsageModel(
	val blobStoreBytes: ULong,
	val databaseBytes: ULong,
	val logsBytes: ULong,
	val previewsBytes: ULong,
	val otherCoreBytes: ULong,
) {
	val appDataBytes: ULong get() = databaseBytes + logsBytes + previewsBytes + otherCoreBytes
}

data class ReceivedArtifactModel(
	val id: String,
	val locator: String,
	val locatorKind: uniffi.vnidrop.ReceivedLocatorKind,
	val logicalSize: ULong,
)

sealed interface CoreSignal {
	data class ApprovalChanged(val transferId: ULong) : CoreSignal
	data class ReceiverHistoryChanged(val transferId: ULong) : CoreSignal
	/** Transfer status/history changed enough to re-read the durable snapshot. */
	data class TransfersChanged(val transferId: ULong) : CoreSignal
	/** Pairing / saved-device state changed; refresh eligibility, relationships, and saved list. */
	data object PairingChanged : CoreSignal
	/** Targeted-transfer offer or lifecycle changed; refresh pending offers and transfers. */
	data object TargetedTransferChanged : CoreSignal
}

interface CoreGateway {
	val state: StateFlow<CoreState>
	val signals: SharedFlow<CoreSignal>

	suspend fun initialize(
		appDataDir: String,
		relaySettings: RelaySettings = RelaySettings(),
	): Result<Unit>
	fun shutdown()
	suspend fun sharePath(path: String, transferName: String, senderName: String, accessPolicy: ShareAccessPolicy): Result<Share>
	suspend fun shareFileDescriptor(
		fd: Int,
		displayName: String,
		transferName: String,
		senderName: String,
		accessPolicy: ShareAccessPolicy,
	): Result<Share>
	/** Multi-source share used by multi-file pickers. */
	suspend fun shareSources(
		sources: List<uniffi.vnidrop.ShareSource>,
		transferName: String,
		senderName: String,
		accessPolicy: ShareAccessPolicy,
	): Result<Share>
	suspend fun inspectTicket(ticket: String): Result<TicketInspectionModel>
	suspend fun receive(ticket: String, outputDir: String, receiverName: String): Result<Unit>
	suspend fun receiveWithOutputSink(ticket: String, outputSink: ReceiveOutputSink, receiverName: String): Result<Unit>
	suspend fun receiveWithOutputSinkV2(ticket: String, outputSink: ReceiveOutputSinkV2, receiverName: String): Result<Unit>
	suspend fun storageUsage(): Result<CoreStorageUsageModel>
	suspend fun clearTransferCache(): Result<ULong>
	suspend fun receivedArtifacts(): Result<List<ReceivedArtifactModel>>
	suspend fun cancel(transferId: ULong): Result<Unit>
	suspend fun delete(transferId: ULong): Result<Unit>
	suspend fun clearReceiveHistory(): Result<ULong>
	suspend fun receiverRequests(transferId: ULong): Result<List<ReceiverRequestModel>>
	suspend fun respondReceiverRequest(requestId: String, accepted: Boolean, reason: String? = null): Result<Unit>
	suspend fun refresh(): Result<Unit>

	// Saved devices / targeted transfers
	suspend fun listPairingEligibilities(): Result<List<PairingEligibilityModel>>
	suspend fun declinePairingEligibility(peerEndpointId: String): Result<Unit>
	suspend fun requestSavedDevicePairing(peerEndpointId: String): Result<Boolean>
	suspend fun respondToDevicePairing(peerEndpointId: String, accepted: Boolean): Result<Boolean>
	suspend fun listDeviceRelationships(): Result<List<DeviceRelationshipModel>>
	suspend fun listSavedDevices(): Result<List<SavedDeviceModel>>
	suspend fun setSavedDeviceLabel(peerEndpointId: String, label: String?): Result<Unit>
	suspend fun forgetSavedDevice(peerEndpointId: String): Result<Unit>
	suspend fun blockDevice(peerEndpointId: String): Result<Unit>
	suspend fun unblockDevice(peerEndpointId: String): Result<Unit>
	suspend fun listBlockedDevices(): Result<List<String>>
	suspend fun listPendingTargetedOffers(): Result<List<PendingTargetedOfferModel>>
	suspend fun respondToTargetedOffer(transferId: String, accepted: Boolean): Result<TargetedOfferResponseModel>
	suspend fun createTargetedTransfer(
		receiverEndpointId: String,
		sources: List<uniffi.vnidrop.ShareSource>,
		transferName: String?,
	): Result<TargetedTransferModel>
	suspend fun getTargetedTransfer(id: String): Result<TargetedTransferModel?>
	suspend fun listTargetedTransfers(): Result<List<TargetedTransferModel>>
	suspend fun receiveTargetedTransfer(transferId: String, outputDir: String): Result<Unit>
	suspend fun receiveTargetedTransferWithOutputSink(
		transferId: String,
		outputSink: ReceiveOutputSink,
	): Result<Unit>
	suspend fun receiveTargetedTransferWithOutputSinkV2(
		transferId: String,
		outputSink: ReceiveOutputSinkV2,
	): Result<Unit>
	suspend fun resumeTargetedTransfer(id: String, outputDir: String): Result<Unit>
	suspend fun resumeTargetedTransferWithOutputSinkV2(id: String, outputSink: ReceiveOutputSinkV2): Result<Unit>
	suspend fun cancelTargetedTransfer(id: String): Result<Unit>
	suspend fun deleteTargetedTransfer(id: String): Result<Unit>
}
