package de.tsschulz.tt_tagebuch.app.pdf

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.pdf.PdfDocument
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
import de.tsschulz.tt_tagebuch.shared.api.models.DiaryDateActivityItem
import de.tsschulz.tt_tagebuch.shared.api.models.DiaryFreeformActivity
import de.tsschulz.tt_tagebuch.shared.api.models.DiaryTrainingParticipant
import de.tsschulz.tt_tagebuch.shared.api.models.DiaryPlanGroup
import de.tsschulz.tt_tagebuch.shared.api.models.Member
import de.tsschulz.tt_tagebuch.shared.api.models.displayTitle
import de.tsschulz.tt_tagebuch.shared.api.models.isPresentParticipant
import java.io.File
import java.io.FileOutputStream
import java.util.Locale

private const val PAGE_W = 595
private const val PAGE_H = 842
private const val MARGIN = 40f
private const val MAX_TEXT_W = (PAGE_W - MARGIN * 2).toInt()

private fun newTitlePaint(): TextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
    color = Color.BLACK
    textSize = 16f
    typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
}

private fun newBodyPaint(): TextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
    color = Color.BLACK
    textSize = 11f
    typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
    textLocale = Locale.GERMANY
}

private fun Canvas.drawStatic(text: String, paint: TextPaint, x: Float, y: Float): Float {
    if (text.isEmpty()) return y
    val layout = StaticLayout.Builder.obtain(text, 0, text.length, paint, MAX_TEXT_W)
        .setAlignment(Layout.Alignment.ALIGN_NORMAL)
        .setLineSpacing(0f, 1.05f)
        .setIncludePad(false)
        .build()
    save()
    translate(x, y)
    layout.draw(this)
    restore()
    return y + layout.height + 6f
}

fun writeTrainingPlanPdf(
    outFile: File,
    clubName: String,
    dateLabel: String,
    timeLabel: String,
    planItems: List<DiaryDateActivityItem>,
    timeblockFallback: String,
) {
    val doc = PdfDocument()
    var pageSeq = 0
    fun openPage(): PdfDocument.Page {
        pageSeq++
        return doc.startPage(PdfDocument.PageInfo.Builder(PAGE_W, PAGE_H, pageSeq).create())
    }
    var page = openPage()
    var canvas = page.canvas
    var y = MARGIN
    val titlePaint = newTitlePaint()
    val bodyPaint = newBodyPaint()
    fun newPageIfNeeded(extra: Float) {
        if (y + extra > PAGE_H - MARGIN) {
            doc.finishPage(page)
            page = openPage()
            canvas = page.canvas
            y = MARGIN
        }
    }
    y = canvas.drawStatic("Trainingsplan – $clubName", titlePaint, MARGIN, y)
    y = canvas.drawStatic("Datum: $dateLabel", bodyPaint, MARGIN, y)
    y = canvas.drawStatic("Zeiten: $timeLabel", bodyPaint, MARGIN, y)
    y = canvas.drawStatic("", bodyPaint, MARGIN, y)
    val sorted = planItems.sortedWith(compareBy({ it.groupId ?: 0 }, { it.orderId }, { it.id }))
    sorted.forEach { item ->
        val line = buildString {
            append(item.displayTitle(timeblockFallback).ifBlank { "Eintrag ${item.id}" })
            item.durationText?.takeIf { it.isNotBlank() }?.let { append(" — $it") }
                ?: item.duration?.let { append(" — ${it} min") }
            item.planGroup?.name?.takeIf { it.isNotBlank() }?.let { append(" — Gruppe: $it") }
        }
        newPageIfNeeded(40f)
        y = canvas.drawStatic("• $line", bodyPaint, MARGIN, y)
    }
    doc.finishPage(page)
    FileOutputStream(outFile).use { doc.writeTo(it) }
    doc.close()
}

fun writeTrainingDaySummaryPdf(
    outFile: File,
    clubName: String,
    dateLabel: String,
    timeLabel: String,
    activeMembers: List<Member>,
    participants: List<DiaryTrainingParticipant>,
    freeform: List<DiaryFreeformActivity>,
    planItems: List<DiaryDateActivityItem>,
    planGroups: List<DiaryPlanGroup>,
    activityParticipantRows: Map<Int, List<Int>>,
    timeblockFallback: String,
) {
    val doc = PdfDocument()
    var pageSeq = 0
    fun openPage(): PdfDocument.Page {
        pageSeq++
        return doc.startPage(PdfDocument.PageInfo.Builder(PAGE_W, PAGE_H, pageSeq).create())
    }
    var page = openPage()
    var canvas = page.canvas
    var y = MARGIN
    val titlePaint = newTitlePaint()
    val bodyPaint = newBodyPaint()
    fun newPageIfNeeded(extra: Float) {
        if (y + extra > PAGE_H - MARGIN) {
            doc.finishPage(page)
            page = openPage()
            canvas = page.canvas
            y = MARGIN
        }
    }
    y = canvas.drawStatic("Trainingstag – $clubName", titlePaint, MARGIN, y)
    y = canvas.drawStatic("Datum: $dateLabel", bodyPaint, MARGIN, y)
    y = canvas.drawStatic("Zeiten: $timeLabel", bodyPaint, MARGIN, y)
    y = canvas.drawStatic("", bodyPaint, MARGIN, y)

    y = canvas.drawStatic("Teilnehmer (laut App-Stand)", titlePaint, MARGIN, y)
    val partLines = activeMembers.map { m ->
        val row = participants.find { it.memberId == m.id }
        val base = "${m.lastName}, ${m.firstName}"
        if (row == null) {
            "$base — (keine Teilnahme-Zeile)"
        } else if (row.isPresentParticipant()) {
            "$base — anwesend"
        } else {
            when (row.attendanceStatus?.lowercase()) {
                "excused" -> "$base — entschuldigt"
                "cancelled" -> "$base — abgesagt"
                else -> "$base — (${row.attendanceStatus ?: "?"})"
            }
        }
    }
    if (partLines.isEmpty()) {
        y = canvas.drawStatic("—", bodyPaint, MARGIN, y)
    } else {
        partLines.forEach { n ->
            newPageIfNeeded(30f)
            y = canvas.drawStatic("• $n", bodyPaint, MARGIN, y)
        }
    }

    y = canvas.drawStatic("", bodyPaint, MARGIN, y)
    y = canvas.drawStatic("Weitere Tages-Aktivitäten", titlePaint, MARGIN, y)
    if (freeform.isEmpty()) {
        y = canvas.drawStatic("—", bodyPaint, MARGIN, y)
    } else {
        freeform.forEach { f ->
            newPageIfNeeded(30f)
            y = canvas.drawStatic("• ${f.description}", bodyPaint, MARGIN, y)
        }
    }

    y = canvas.drawStatic("", bodyPaint, MARGIN, y)
    y = canvas.drawStatic("Trainingsplan (Aktivitäten)", titlePaint, MARGIN, y)
    val sorted = planItems.sortedWith(compareBy({ it.groupId ?: 0 }, { it.orderId }, { it.id }))
    if (sorted.isEmpty()) {
        y = canvas.drawStatic("—", bodyPaint, MARGIN, y)
    } else {
        sorted.forEach { item ->
            newPageIfNeeded(40f)
            val line = buildString {
                append(item.displayTitle(timeblockFallback).ifBlank { "Eintrag ${item.id}" })
                item.groupId?.let { gid ->
                    val groupName = planGroups.find { it.id == gid }?.name ?: "Gruppe $gid"
                    append(" [$groupName]")
                }
                item.durationText?.takeIf { it.isNotBlank() }?.let { append(" — $it") }
                    ?: item.duration?.let { append(" — ${it} min") }
            }
            y = canvas.drawStatic("• $line", bodyPaint, MARGIN, y)
            val assigned = activityParticipantRows[item.id].orEmpty().mapNotNull { participantId ->
                val participant = participants.find { it.id == participantId } ?: return@mapNotNull null
                activeMembers.find { it.id == participant.memberId }?.let { "${it.firstName} ${it.lastName}" }
            }
            if (assigned.isNotEmpty()) {
                y = canvas.drawStatic("  Teilnehmer: ${assigned.joinToString(", ")}", bodyPaint, MARGIN, y)
            }
            item.groupActivities.forEach { nested ->
                val nestedId = nested.id ?: return@forEach
                val nestedAssigned = activityParticipantRows[nestedId].orEmpty().mapNotNull { participantId ->
                    val participant = participants.find { it.id == participantId } ?: return@mapNotNull null
                    activeMembers.find { it.id == participant.memberId }?.let { "${it.firstName} ${it.lastName}" }
                }
                val nestedTitle = nested.groupPredefinedActivity?.name ?: nested.groupPredefinedActivity?.code ?: "Gruppenaktivitaet"
                y = canvas.drawStatic("  - $nestedTitle", bodyPaint, MARGIN, y)
                if (nestedAssigned.isNotEmpty()) {
                    y = canvas.drawStatic("    Teilnehmer: ${nestedAssigned.joinToString(", ")}", bodyPaint, MARGIN, y)
                }
            }
        }
    }

    doc.finishPage(page)
    FileOutputStream(outFile).use { doc.writeTo(it) }
    doc.close()
}
