package de.tsschulz.timeclock.ui.booking

import android.app.DatePickerDialog
import android.app.TimePickerDialog
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.tsschulz.timeclock.data.api.CalendarDayDto
import de.tsschulz.timeclock.data.api.CalendarDto
import de.tsschulz.timeclock.data.api.SickEntryDto
import de.tsschulz.timeclock.data.api.TimefixDto
import de.tsschulz.timeclock.data.api.VacationDto
import de.tsschulz.timeclock.data.api.WorkdaysDto
import de.tsschulz.timeclock.data.api.WorklogEntryDto
import de.tsschulz.timeclock.ui.components.TcButton
import de.tsschulz.timeclock.ui.components.TcCard
import de.tsschulz.timeclock.ui.components.TcError
import de.tsschulz.timeclock.ui.components.TcLoading
import de.tsschulz.timeclock.ui.components.TcTextField
import de.tsschulz.timeclock.ui.model.ButtonVariant
import de.tsschulz.timeclock.ui.theme.TcColors
import de.tsschulz.timeclock.ui.theme.TcRadius
import de.tsschulz.timeclock.ui.theme.TcSpacing
import java.time.LocalDate
import java.time.YearMonth
import java.time.format.DateTimeFormatter
import java.util.Locale
import kotlin.math.roundToInt

@Composable
fun VacationScreen(state: BookingUiState, isTablet: Boolean, onCreate: (Int, String, String?) -> Unit, onDelete: (String) -> Unit) {
    var type by rememberSaveable { mutableStateOf("0") }
    var start by rememberSaveable { mutableStateOf(LocalDate.now().toString()) }
    var end by rememberSaveable { mutableStateOf(LocalDate.now().toString()) }
    Phase4Frame(loading = state.vacationLoading, error = state.vacationError) {
        FormCard("Urlaub eintragen", isTablet) {
            FieldLabel("Umfang")
            Row(horizontalArrangement = Arrangement.spacedBy(TcSpacing.Sm)) {
                TcButton("Zeitraum", variant = if (type == "0") ButtonVariant.Primary else ButtonVariant.Default, onClick = { type = "0" })
                TcButton("Halber Tag", variant = if (type == "1") ButtonVariant.Primary else ButtonVariant.Default, onClick = {
                    type = "1"
                    end = start
                })
            }
            DateField("Urlaubsbeginn", start, {
                start = it
                if (type == "1") end = it
            })
            if (type != "1") {
                DateField("Urlaubsende", end, { end = it })
            }
            TcButton("Urlaub eintragen", variant = ButtonVariant.Primary, onClick = {
                val typeValue = type.toIntOrNull() ?: 0
                onCreate(typeValue, start, if (typeValue == 1) start else end)
            })
        }
        ListCard("Urlaubseinträge", state.vacations) { item ->
            VacationRow(item, onDelete)
        }
    }
}

@Composable
fun SickScreen(state: BookingUiState, isTablet: Boolean, onCreate: (String, String, String?) -> Unit, onDelete: (String) -> Unit) {
    var start by rememberSaveable { mutableStateOf(LocalDate.now().toString()) }
    var end by rememberSaveable { mutableStateOf(LocalDate.now().toString()) }
    var typeId by rememberSaveable { mutableStateOf(state.sickTypes.firstOrNull()?.id?.toString().orEmpty()) }
    LaunchedEffect(state.sickTypes) {
        if (typeId.isBlank()) typeId = state.sickTypes.firstOrNull()?.id.orEmpty()
    }
    Phase4Frame(loading = state.sickLoading, error = state.sickError) {
        FormCard("Erkrankung eintragen", isTablet) {
            DateField("Erster Krankheitstag", start, { start = it })
            DateField("Letzter Krankheitstag", end, { end = it })
            FieldLabel("Krankheitstyp")
            FlowRow(horizontalArrangement = Arrangement.spacedBy(TcSpacing.Sm), verticalArrangement = Arrangement.spacedBy(TcSpacing.Sm)) {
                state.sickTypes.forEach { type ->
                    TcButton(
                        text = type.name,
                        variant = if (type.id == typeId) ButtonVariant.Primary else ButtonVariant.Default,
                        onClick = { typeId = type.id },
                    )
                }
            }
            TcButton("Erkrankung eintragen", variant = ButtonVariant.Primary, onClick = {
                if (typeId.isNotBlank()) onCreate(typeId, start, end.ifBlank { start })
            })
        }
        ListCard("Krankheitseinträge", state.sickEntries) { item ->
            SickRow(item, onDelete)
        }
    }
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun TimefixScreen(
    state: BookingUiState,
    isTablet: Boolean,
    onDate: (String) -> Unit,
    onCreate: (String, String, String, String) -> Unit,
    onDelete: (String) -> Unit,
) {
    var worklogId by rememberSaveable { mutableStateOf("") }
    var newDate by rememberSaveable { mutableStateOf(state.timefixDate) }
    var time by rememberSaveable { mutableStateOf("08:00") }
    var action by rememberSaveable { mutableStateOf("start work") }
    LaunchedEffect(state.worklogEntries) {
        val selectedStillExists = state.worklogEntries.any { it.id == worklogId }
        if (worklogId.isBlank() || !selectedStillExists) {
            val first = state.worklogEntries.firstOrNull()
            worklogId = first?.id.orEmpty()
            first?.time?.let { time = it }
            first?.action?.let { action = it }
        }
    }
    LaunchedEffect(state.timefixDate) {
        if (newDate.isBlank()) newDate = state.timefixDate
    }
    Phase4Frame(loading = state.timefixLoading, error = state.timefixError) {
        FormCard("Zeitkorrektur", isTablet) {
            DateField("Datum des Original-Eintrags", state.timefixDate, onDate)
            WorklogDropdown(
                entries = state.worklogEntries,
                selectedId = worklogId,
                onSelect = { entry ->
                    worklogId = entry.id
                    entry.time?.let { time = it }
                    entry.action?.let { action = it }
                },
            )
            DateField("Neues Datum", newDate, { newDate = it })
            TimeField("Neue Uhrzeit", time, { time = it })
            ActionDropdown(action, { action = it })
            TcButton("Korrektur erstellen", variant = ButtonVariant.Primary, onClick = {
                if (worklogId.isNotBlank()) onCreate(worklogId, newDate, time, action)
            })
            if (state.worklogEntries.isEmpty()) {
                Text("Für dieses Datum sind keine Worklog-Einträge vorhanden.", color = TcColors.TextMuted, fontSize = 13.sp)
            }
        }
        ListCard("Worklog-Einträge am Datum", state.worklogEntries) { item -> WorklogRow(item) }
        ListCard("Zeitkorrekturen heute", state.timefixes) { item -> TimefixRow(item, onDelete) }
    }
}

@Composable
fun WorkdaysScreen(state: BookingUiState, onYear: (Int) -> Unit) {
    var selectedYear by rememberSaveable { mutableStateOf(state.workdaysYear) }
    LaunchedEffect(state.workdaysYear) {
        selectedYear = state.workdaysYear
    }
    Phase4Frame(loading = state.workdaysLoading, error = state.workdaysError) {
        FormCard("Arbeitstage", isTablet = false) {
            YearDropdown(selectedYear) { year ->
                selectedYear = year
                onYear(year)
            }
        }
        WorkdaysCard(state.workdays)
    }
}

@Composable
fun CalendarScreen(state: BookingUiState, onMonth: (Int) -> Unit) {
    Phase4Frame(loading = state.calendarLoading, error = state.calendarError) {
        TcCard {
            Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                TcButton("←", variant = ButtonVariant.Secondary, onClick = { onMonth(-1) })
                Text(
                    text = YearMonth.of(state.calendarYear, state.calendarMonth)
                        .format(DateTimeFormatter.ofPattern("MMMM yyyy", Locale.GERMANY)),
                    color = TcColors.Text,
                    fontSize = 18.sp,
                    fontWeight = FontWeight.SemiBold,
                )
                TcButton("→", variant = ButtonVariant.Secondary, onClick = { onMonth(1) })
            }
        }
        CalendarGrid(state.calendar)
    }
}

@Composable
private fun Phase4Frame(loading: Boolean, error: String?, content: @Composable () -> Unit) {
    if (loading) TcLoading("Lade Daten...")
    error?.let { TcError(it) }
    content()
}

@Composable
private fun FormCard(title: String, isTablet: Boolean, content: @Composable ColumnScope.() -> Unit) {
    TcCard {
        SectionTitle(title)
        Column(verticalArrangement = Arrangement.spacedBy(TcSpacing.Md), content = content)
    }
}

@Composable
private fun DateField(label: String, value: String, onValueChange: (String) -> Unit) {
    val context = LocalContext.current
    val parsed = runCatching { LocalDate.parse(value) }.getOrDefault(LocalDate.now())
    FieldLabel(label)
    TcButton(
        text = parsed.format(DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.GERMANY)),
        variant = ButtonVariant.Default,
        modifier = Modifier.fillMaxWidth(),
        onClick = {
            DatePickerDialog(
                context,
                { _, year, month, day ->
                    onValueChange(LocalDate.of(year, month + 1, day).toString())
                },
                parsed.year,
                parsed.monthValue - 1,
                parsed.dayOfMonth,
            ).show()
        },
    )
}

@Composable
private fun TimeField(label: String, value: String, onValueChange: (String) -> Unit) {
    val context = LocalContext.current
    val parts = value.split(":")
    val hour = parts.getOrNull(0)?.toIntOrNull() ?: 8
    val minute = parts.getOrNull(1)?.toIntOrNull() ?: 0
    FieldLabel(label)
    TcButton(
        text = "%02d:%02d".format(hour, minute),
        variant = ButtonVariant.Default,
        modifier = Modifier.fillMaxWidth(),
        onClick = {
            TimePickerDialog(
                context,
                { _, selectedHour, selectedMinute ->
                    onValueChange("%02d:%02d".format(selectedHour, selectedMinute))
                },
                hour,
                minute,
                true,
            ).show()
        },
    )
}

@Composable
private fun WorklogDropdown(
    entries: List<WorklogEntryDto>,
    selectedId: String,
    onSelect: (WorklogEntryDto) -> Unit,
) {
    var expanded by rememberSaveable { mutableStateOf(false) }
    val selected = entries.firstOrNull { it.id == selectedId }
    FieldLabel("Eintrag")
    Box(modifier = Modifier.fillMaxWidth()) {
        TcButton(
            text = selected?.toWorklogLabel() ?: if (entries.isEmpty()) "Keine Einträge für dieses Datum" else "Bitte wählen",
            variant = ButtonVariant.Default,
            modifier = Modifier.fillMaxWidth(),
            onClick = { if (entries.isNotEmpty()) expanded = true },
        )
        DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
            entries.forEach { entry ->
                DropdownMenuItem(
                    text = { Text(entry.toWorklogLabel(), color = TcColors.Text) },
                    onClick = {
                        onSelect(entry)
                        expanded = false
                    },
                )
            }
        }
    }
}

@Composable
private fun ActionDropdown(value: String, onValueChange: (String) -> Unit) {
    var expanded by rememberSaveable { mutableStateOf(false) }
    val actions = listOf("start work", "stop work", "start pause", "stop pause")
    FieldLabel("Neuer Eintrags-Typ")
    Box(modifier = Modifier.fillMaxWidth()) {
        TcButton(
            text = value.toActionLabel(),
            variant = ButtonVariant.Default,
            modifier = Modifier.fillMaxWidth(),
            onClick = { expanded = true },
        )
        DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
            actions.forEach { action ->
                DropdownMenuItem(
                    text = { Text(action.toActionLabel(), color = TcColors.Text) },
                    onClick = {
                        onValueChange(action)
                        expanded = false
                    },
                )
            }
        }
    }
}

@Composable
private fun YearDropdown(value: Int, onValueChange: (Int) -> Unit) {
    var expanded by rememberSaveable { mutableStateOf(false) }
    val years = 2000..2100
    FieldLabel("Jahr")
    Box(modifier = Modifier.fillMaxWidth()) {
        TcButton(
            text = value.toString(),
            variant = ButtonVariant.Default,
            modifier = Modifier.fillMaxWidth(),
            onClick = { expanded = true },
        )
        DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
            years.forEach { year ->
                DropdownMenuItem(
                    text = { Text(year.toString(), color = TcColors.Text) },
                    onClick = {
                        onValueChange(year)
                        expanded = false
                    },
                )
            }
        }
    }
}

@Composable
private fun FieldLabel(label: String) {
    Text(
        text = label,
        color = Color333,
        fontWeight = FontWeight.Medium,
        fontSize = 14.sp,
        modifier = Modifier.padding(bottom = TcSpacing.Sm),
    )
}

@Composable
private fun <T> ListCard(title: String, items: List<T>, row: @Composable (T) -> Unit) {
    TcCard {
        SectionTitle(title)
        if (items.isEmpty()) {
            Text("Keine Einträge vorhanden.", color = TcColors.TextMuted, fontSize = 14.sp)
        } else {
            Column(verticalArrangement = Arrangement.spacedBy(TcSpacing.Sm)) {
                items.forEach { item -> row(item) }
            }
        }
    }
}

@Composable
private fun VacationRow(item: VacationDto, onDelete: (String) -> Unit) = DataRow(
    title = item.type ?: "Urlaub",
    details = "${item.startDate.toDisplayDate()} - ${item.endDate.toDisplayDate()}",
    onDelete = { onDelete(item.id) },
)

@Composable
private fun SickRow(item: SickEntryDto, onDelete: (String) -> Unit) = DataRow(
    title = item.sickTypeName ?: "Krankheit",
    details = "${item.startDate.toDisplayDate()} - ${item.endDate.toDisplayDate()}",
    onDelete = { onDelete(item.id) },
)

@Composable
private fun TimefixRow(item: TimefixDto, onDelete: (String) -> Unit) = DataRow(
    title = item.newAction?.toActionLabel() ?: "Zeitkorrektur",
    details = "${item.originalDate.toDisplayDate()} ${item.originalTime ?: "—"} → ${item.newDate.toDisplayDate()} ${item.newTime ?: "—"}",
    onDelete = { onDelete(item.id) },
)

@Composable
private fun WorklogRow(item: WorklogEntryDto) = DataRow(
    title = item.action?.toActionLabel() ?: "Eintrag",
    details = "${item.time ?: "—"} (${item.tstamp ?: "—"})",
)

@Composable
private fun DataRow(title: String, details: String, onDelete: (() -> Unit)? = null) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .background(TcColors.Background, RoundedCornerShape(TcRadius.Medium))
            .border(1.dp, TcColors.Border, RoundedCornerShape(TcRadius.Medium))
            .padding(TcSpacing.Md),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(TcSpacing.Md),
    ) {
        Column(modifier = Modifier.weight(1f)) {
            Text(title, color = TcColors.Text, fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
            Text(details, color = TcColors.TextMuted, fontSize = 13.sp)
        }
        onDelete?.let { TcButton("Löschen", variant = ButtonVariant.Danger, onClick = it) }
    }
}

@Composable
private fun WorkdaysCard(data: WorkdaysDto?) {
    TcCard {
        SectionTitle("Jahresstatistik")
        if (data == null) {
            Text("Keine Statistik geladen.", color = TcColors.TextMuted)
        } else {
            Detail("Jahr", data.year.toString())
            Detail("Werktage", data.workdays.toString())
            Detail("Feiertage", data.holidays.toString())
            Detail("Urlaubstage", data.vacationDays.toString())
            Detail("Krankheitstage", "${data.sickDays} (${data.sickPercentage}%)")
            Detail("Gearbeitete Tage", data.workedDays.toString())
        }
    }
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun CalendarGrid(data: CalendarDto?) {
    TcCard {
        SectionTitle("Kalender")
        if (data == null) {
            Text("Kein Kalender geladen.", color = TcColors.TextMuted)
        } else {
            Column(verticalArrangement = Arrangement.spacedBy(TcSpacing.Sm)) {
                data.weeks.forEach { week ->
                    FlowRow(horizontalArrangement = Arrangement.spacedBy(TcSpacing.Sm), verticalArrangement = Arrangement.spacedBy(TcSpacing.Sm)) {
                        week.forEach { CalendarCell(it) }
                    }
                }
            }
        }
    }
}

@Composable
private fun CalendarCell(day: CalendarDayDto) {
    val bg = when {
        day.isToday -> TcColors.ActiveMenu
        !day.isCurrentMonth -> TcColors.Card
        else -> TcColors.Background
    }
    Column(
        modifier = Modifier
            .width(92.dp)
            .background(bg, RoundedCornerShape(TcRadius.Medium))
            .border(1.dp, TcColors.Border, RoundedCornerShape(TcRadius.Medium))
            .padding(TcSpacing.Sm),
    ) {
        Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.Bottom) {
            Text(day.toWeekdayLabel(), color = TcColors.TextMuted, fontSize = 11.sp)
            Text(day.day.toString(), color = TcColors.Text, fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
        }
        day.holiday?.let { Text(it, color = TcColors.Danger, fontSize = 11.sp) }
        if (day.sick) Text("Krank", color = TcColors.Secondary, fontSize = 11.sp)
        day.vacation?.let { Text(if (it == "half") "Urlaub 1/2" else "Urlaub", color = TcColors.Primary, fontSize = 11.sp) }
        day.workedHours?.let { Text(it.toHourMinuteLabel(), color = TcColors.TextMuted, fontSize = 11.sp) }
    }
}

@Composable
private fun SectionTitle(text: String) {
    Text(text, color = TcColors.Text, fontSize = 18.sp, fontWeight = FontWeight.SemiBold, modifier = Modifier.padding(bottom = TcSpacing.Md))
}

@Composable
private fun Detail(label: String, value: String) {
    Row(modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp), horizontalArrangement = Arrangement.SpaceBetween) {
        Text("$label:", color = TcColors.TextMuted, fontSize = 14.sp)
        Text(value, color = TcColors.Text, fontSize = 14.sp)
    }
}

private fun String?.toDisplayDate(): String {
    if (this.isNullOrBlank()) return "—"
    return runCatching {
        LocalDate.parse(this.substring(0, 10)).format(DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.GERMANY))
    }.getOrDefault(this)
}

private fun String.toActionLabel(): String =
    when (this) {
        "start work" -> "Arbeit beginnen"
        "stop work" -> "Arbeit beenden"
        "start pause" -> "Pause beginnen"
        "stop pause" -> "Pause beenden"
        else -> this
    }

private fun WorklogEntryDto.toWorklogLabel(): String =
    "${time ?: "—"} - ${(action ?: "—").toActionLabel()}"

private fun CalendarDayDto.toWeekdayLabel(): String =
    runCatching {
        LocalDate.parse(date).format(DateTimeFormatter.ofPattern("EEE", Locale.GERMANY))
    }.getOrDefault("")

private fun Double.toHourMinuteLabel(): String {
    val totalMinutes = (this * 60).roundToInt().coerceAtLeast(0)
    val hours = totalMinutes / 60
    val minutes = totalMinutes % 60
    return "%d:%02d".format(hours, minutes)
}

private val Color333 = androidx.compose.ui.graphics.Color(0xFF333333)
