package de.arxsilex.maptools.converter.desktop

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.arxsilex.maptools.converter.core.InputFileInfo
import de.arxsilex.maptools.converter.desktop.generated.resources.Res
import de.arxsilex.maptools.converter.desktop.generated.resources.map_source
import org.jetbrains.compose.resources.painterResource

internal data class InputFileRejection(
    val fileName: String,
    val path: String,
    val reason: String,
)

@Composable
internal fun SourceStep(
    inputFiles: List<InputFileInfo>,
    inputErrors: List<InputFileRejection>,
    portableStorageStatus: PortableStorageStatus,
    onChooseInputs: () -> Unit,
    onChooseArchive: () -> Unit,
    onRemoveInput: (InputFileInfo) -> Unit,
    onNext: () -> Unit,
    onConvertWholeFile: () -> Unit,
) {
    val strings = LocalAppStrings.current
    Column(
        modifier = Modifier.fillMaxSize().padding(32.dp),
        verticalArrangement = Arrangement.spacedBy(24.dp),
    ) {
        ScreenTitle(
            title = strings["step.source"],
            description = strings["source.description_all"],
        )
        CardContainer(modifier = Modifier.fillMaxWidth().weight(1f)) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                Image(
                    painter = painterResource(Res.drawable.map_source),
                    contentDescription = null,
                    modifier = Modifier.size(64.dp),
                )
                Spacer(Modifier.width(18.dp))
                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = when (inputFiles.size) {
                            0 -> strings["source.none"]
                            1 -> if (inputFiles.single().format == de.arxsilex.maptools.converter.core.InputFormat.MAPSFORGE_POI) {
                                strings["source.one_poi"]
                            } else if (inputFiles.single().format.isElevationData) {
                                strings["source.one_elevation"]
                            } else {
                                strings["source.one_map"]
                            }
                            else -> strings("source.status_multiple", inputFiles.size)
                        },
                        fontWeight = FontWeight.SemiBold,
                        fontSize = 17.sp,
                    )
                    if (inputFiles.isEmpty()) {
                        Text(
                            strings["source.supported_all"],
                            color = MaterialTheme.colorScheme.onSurfaceVariant,
                        )
                        Text(
                            strings["source.supported_archives"],
                            color = MaterialTheme.colorScheme.onSurfaceVariant,
                            fontSize = 12.sp,
                        )
                    } else {
                        Text(
                            strings("source.total_size", formatFileSize(inputFiles.sumOf(InputFileInfo::sizeBytes))),
                            color = MaterialTheme.colorScheme.primary,
                        )
                        Text(
                            strings["source.more_hint"],
                            color = MaterialTheme.colorScheme.onSurfaceVariant,
                            fontSize = 12.sp,
                        )
                    }
                    if (inputErrors.isNotEmpty()) {
                        Text(
                            if (inputErrors.size == 1) {
                                strings["source.rejected_one"]
                            } else {
                                strings("source.rejected_many", inputErrors.size)
                            },
                            color = MaterialTheme.colorScheme.error,
                            fontWeight = FontWeight.SemiBold,
                        )
                    }
                    Text(
                        strings("source.portable_storage", portableStorageStatus.directory),
                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                        fontSize = 11.sp,
                    )
                    Text(
                        strings("source.free_storage", formatFileSize(portableStorageStatus.usableBytes)),
                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                        fontSize = 11.sp,
                    )
                    if (inputFiles.isNotEmpty() && !portableStorageStatus.hasEnoughSpace) {
                        Text(
                            strings("source.low_storage", formatFileSize(portableStorageStatus.requiredBytes)),
                            color = MaterialTheme.colorScheme.error,
                            fontSize = 12.sp,
                            fontWeight = FontWeight.SemiBold,
                        )
                    }
                }
            }
            Spacer(Modifier.height(18.dp))
            Column(
                modifier = Modifier.fillMaxWidth().weight(1f).verticalScroll(rememberScrollState()),
                verticalArrangement = Arrangement.spacedBy(10.dp),
            ) {
                if (inputErrors.isNotEmpty()) {
                    Text(
                        strings["source.not_added"],
                        color = MaterialTheme.colorScheme.error,
                        fontWeight = FontWeight.SemiBold,
                    )
                    inputErrors.forEach { rejection ->
                        RejectedInputCard(rejection)
                    }
                    Spacer(Modifier.height(6.dp))
                }
                inputFiles.forEach { inputFile ->
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        verticalAlignment = Alignment.CenterVertically,
                    ) {
                        Column(modifier = Modifier.weight(1f)) {
                            Text(inputFile.name, fontWeight = FontWeight.SemiBold)
                            Text(
                                "${inputFile.format.displayName} · ${formatFileSize(inputFile.sizeBytes)}",
                                color = MaterialTheme.colorScheme.primary,
                            )
                            inputFile.bounds?.let { bounds ->
                                Text(
                                    "${formatCoordinate(bounds.west)} / ${formatCoordinate(bounds.south)} ${strings["source.to"]} " +
                                        "${formatCoordinate(bounds.east)} / ${formatCoordinate(bounds.north)}",
                                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                                    fontSize = 12.sp,
                                )
                            }
                            inputFile.mapsforgeMetadata?.let { metadata ->
                                Text(
                                    strings("source.map_metadata", metadata.fileVersion, metadata.zoomLevelMin, metadata.zoomLevelMax),
                                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                                    fontSize = 12.sp,
                                )
                            }
                            inputFile.mapsforgePoiMetadata?.let { metadata ->
                                Text(
                                    strings("source.poi_metadata", metadata.schemaVersion, metadata.poiCount),
                                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                                    fontSize = 12.sp,
                                )
                            }
                            inputFile.elevationMetadata?.let { metadata ->
                                Text(
                                    buildString {
                                        append("${metadata.width} × ${metadata.height}")
                                        metadata.resolutionMeters?.let { append(" · ${"%.1f".format(it)} m") }
                                        metadata.coordinateReferenceSystem?.let { append(" · $it") }
                                    },
                                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                                    fontSize = 12.sp,
                                )
                            }
                            Text(inputFile.path, color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 11.sp)
                        }
                        Spacer(Modifier.width(12.dp))
                        OutlinedButton(onClick = { onRemoveInput(inputFile) }) { Text(strings["common.remove"]) }
                    }
                }
            }
            Spacer(Modifier.height(12.dp))
            Row(
                modifier = Modifier.align(Alignment.End),
                horizontalArrangement = Arrangement.spacedBy(10.dp),
            ) {
                OutlinedButton(onClick = onChooseArchive) {
                    Text(strings["source.add_archive"])
                }
                Button(onClick = onChooseInputs) {
                    Text(strings[if (inputFiles.isEmpty()) "source.choose_first" else "source.add_more"])
                }
            }
        }
        if (inputFiles.size == 1) {
            OutlinedButton(onClick = onConvertWholeFile, modifier = Modifier.align(Alignment.End)) {
                Text(strings["source.convert_whole"])
            }
        }
        WorkflowFooter(
            status = when (inputFiles.size) {
                0 -> strings["source.status_choose"]
                1 -> strings["source.status_ready"]
                else -> strings("source.status_multiple", inputFiles.size)
            },
            onNext = onNext,
            nextLabel = strings["source.next_area"],
            nextEnabled = inputFiles.isNotEmpty(),
        )
    }
}

@Composable
private fun RejectedInputCard(rejection: InputFileRejection) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        color = MaterialTheme.colorScheme.errorContainer,
        contentColor = MaterialTheme.colorScheme.onErrorContainer,
        shape = RoundedCornerShape(10.dp),
    ) {
        Column(modifier = Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(3.dp)) {
            Text(rejection.fileName, fontWeight = FontWeight.Bold)
            Text(rejection.reason, fontSize = 12.sp)
            Text(rejection.path, fontSize = 11.sp)
        }
    }
}
