package com.fieldlabel.collector.ui.screens

import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.drawable.BitmapDrawable
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.ContentScale
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import coil.compose.AsyncImage
import com.fieldlabel.collector.domain.model.RoutePoint
import com.fieldlabel.collector.domain.model.SpecimenPhoto
import java.io.File
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.fieldlabel.collector.domain.model.CollectionRecord
import com.fieldlabel.collector.ui.viewmodel.CollectionViewModel
import com.fieldlabel.collector.ui.viewmodel.RouteLogViewModel
import com.fieldlabel.collector.ui.viewmodel.SettingsViewModel
import org.osmdroid.config.Configuration
import org.osmdroid.util.BoundingBox
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Polyline
import org.osmdroid.views.overlay.ScaleBarOverlay
import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import com.fieldlabel.collector.ui.map.TILE_STANDARD
import com.fieldlabel.collector.ui.map.tileAttribution
import com.fieldlabel.collector.ui.map.tileSourceFor

// ── ピンアイコン生成 ──────────────────────────────────────────────────────────

/** ピンスタイルに応じた BitmapDrawable を生成する */
private fun createPinDrawable(
    style: String,
    fillArgb: Int,
    strokeArgb: Int,
    sizePx: Int,
    resources: Resources
): BitmapDrawable {
    val bmp = Bitmap.createBitmap(sizePx, sizePx, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bmp)
    val fill = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = fillArgb
        this.style = Paint.Style.FILL
    }
    val stroke = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = strokeArgb
        this.style = Paint.Style.STROKE
        strokeWidth = sizePx * 0.08f
    }
    val cx = sizePx / 2f
    val cy = sizePx / 2f
    val r  = sizePx / 2f - stroke.strokeWidth

    when (style) {
        "circle" -> {
            canvas.drawCircle(cx, cy, r, fill)
            canvas.drawCircle(cx, cy, r, stroke)
        }
        "star" -> {
            val path = starPath(cx, cy, outerR = r, innerR = r * 0.42f, points = 5)
            canvas.drawPath(path, fill)
            canvas.drawPath(path, stroke)
        }
        "diamond" -> {
            val path = Path().apply {
                moveTo(cx,         cy - r)
                lineTo(cx + r,     cy)
                lineTo(cx,         cy + r)
                lineTo(cx - r,     cy)
                close()
            }
            canvas.drawPath(path, fill)
            canvas.drawPath(path, stroke)
        }
        else -> {
            // default: 涙滴型ピン
            val path = teardropPath(cx, cy, r)
            canvas.drawPath(path, fill)
            canvas.drawPath(path, stroke)
            // 中心に白い小円
            val innerPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                color = strokeArgb
                this.style = Paint.Style.FILL
            }
            canvas.drawCircle(cx, cy - r * 0.3f, r * 0.22f, innerPaint)
        }
    }
    return BitmapDrawable(resources, bmp)
}

private fun starPath(cx: Float, cy: Float, outerR: Float, innerR: Float, points: Int): Path {
    val path = Path()
    val step = Math.PI / points
    for (i in 0 until points * 2) {
        val angle = i * step - Math.PI / 2
        val r = if (i % 2 == 0) outerR else innerR
        val x = cx + (r * Math.cos(angle)).toFloat()
        val y = cy + (r * Math.sin(angle)).toFloat()
        if (i == 0) path.moveTo(x, y) else path.lineTo(x, y)
    }
    path.close()
    return path
}

private fun teardropPath(cx: Float, cy: Float, r: Float): Path {
    // 楕円 + 先端をやや下に伸ばした涙滴
    val path = Path()
    val top  = cy - r * 0.85f
    val bot  = cy + r * 1.05f
    val halfW = r * 0.55f
    path.moveTo(cx, bot)
    path.cubicTo(cx - halfW * 1.5f, cy + r * 0.4f, cx - halfW, top, cx, top)
    path.cubicTo(cx + halfW, top, cx + halfW * 1.5f, cy + r * 0.4f, cx, bot)
    path.close()
    return path
}

// ── 地点グループ ────────────────────────────────────────────────────────────

private data class MapLocationGroup(
    val locationId: String,
    val specimens:  List<CollectionRecord>
) {
    val representativeRecord: CollectionRecord get() = specimens.first()
    val address:  String  get() = representativeRecord.displayLocation
    val altitude: Double? get() = representativeRecord.altitude
    val date: String get() {
        val dates = specimens.map { it.collectionDate }.distinct().sorted()
        return if (dates.size > 1) "${dates.first()}〜${dates.last()}"
        else dates.first().toString()
    }
}

// ════════════════════════════════════════════════════════════════════════════
// AllLocationsMapScreen
// ════════════════════════════════════════════════════════════════════════════

@Composable
fun AllLocationsMapScreen(
    onNavigateToDetail:     (String) -> Unit,
    onNavigateToRouteLogList: () -> Unit = {},
    viewModel:              CollectionViewModel = hiltViewModel(),
    settingsViewModel:      SettingsViewModel   = hiltViewModel(),
    routeLogViewModel:      RouteLogViewModel   = hiltViewModel()
) {
    val context              = LocalContext.current
    val lifecycleOwner       = LocalLifecycleOwner.current
    val records              by viewModel.allRecords.collectAsState(initial = emptyList())
    val firstPhotoByLocation by viewModel.firstPhotoByLocation.collectAsState()

    // ルートログ
    val isRecording      by routeLogViewModel.isRecording.collectAsState()
    val currentRoutePoints by routeLogViewModel.currentRoutePoints.collectAsState()

    // 記録開始ダイアログ
    var showStartDialog by remember { mutableStateOf(false) }
    var routeNameInput  by remember { mutableStateOf("") }

    // 設定値
    val mapTileSource by settingsViewModel.mapTileSource.collectAsState()
    val mapPinStyle   by settingsViewModel.mapPinStyle.collectAsState()

    // Material テーマカラーを Android Color (ARGB Int) として取得
    val primaryArgb   = MaterialTheme.colorScheme.primary.toArgb()
    val onPrimaryArgb = MaterialTheme.colorScheme.onPrimary.toArgb()
    val errorArgb     = MaterialTheme.colorScheme.error.toArgb()

    // OSMDroid 設定を初期化（冪等）
    remember(Unit) {
        Configuration.getInstance().load(
            context,
            context.getSharedPreferences("osmdroid", Context.MODE_PRIVATE)
        )
    }

    // 地点 ID ごとにグループ化
    val locationGroups: List<MapLocationGroup> = remember(records) {
        records
            .groupBy { it.locationId }
            .map { (locationId, specimens) ->
                MapLocationGroup(
                    locationId = locationId,
                    specimens  = specimens.sortedBy { it.specimenNumber }
                )
            }
            .sortedByDescending { it.representativeRecord.collectionDate }
    }

    var selectedGroup by remember { mutableStateOf<MapLocationGroup?>(null) }

    // ポップアップ表示時に FAB を上にスライドさせるためのオフセット計算
    val density = LocalDensity.current
    var popupHeightPx by remember { mutableStateOf(0) }
    val fabBottomPadding by animateDpAsState(
        targetValue   = if (selectedGroup != null) {
            with(density) { popupHeightPx.toDp() } + 12.dp
        } else {
            12.dp
        },
        animationSpec = tween(durationMillis = 300),
        label         = "fabOffset"
    )

    val mapView = remember { MapView(context) }

    // Activity ライフサイクルに同期
    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_RESUME -> mapView.onResume()
                Lifecycle.Event.ON_PAUSE  -> mapView.onPause()
                else                      -> Unit
            }
        }
        lifecycleOwner.lifecycle.addObserver(observer)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
            mapView.onDetach()
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {

        // ── 地図本体 ──────────────────────────────────────────────────────
        Box(modifier = Modifier
            .fillMaxSize()
            .clip(RectangleShape)) {
            AndroidView(
                factory = { ctx ->
                    mapView.apply {
                        setTileSource(TILE_STANDARD)
                        setMultiTouchControls(true)
                        controller.setZoom(5.0)
                        controller.setCenter(GeoPoint(36.5, 136.0))

                        // コンパスオーバーレイ
                        val compass = CompassOverlay(
                            ctx,
                            InternalCompassOrientationProvider(ctx),
                            this
                        )
                        compass.enableCompass()
                        overlays.add(compass)

                        // スケールバーオーバーレイ
                        val scaleBar = ScaleBarOverlay(this).apply {
                            setCentred(false)
                            setAlignBottom(true)
                        }
                        overlays.add(scaleBar)
                    }
                },
                update = { mv ->
                    // ── タイルソース切り替え ──────────────────────────────
                    val tileSource = tileSourceFor(mapTileSource)
                    if (mv.tileProvider.tileSource.name() != tileSource.name()) {
                        mv.setTileSource(tileSource)
                    }

                    // ── マーカー再構築（コンパス・スケールバーは先頭に保持） ──
                    // overlays[0] = CompassOverlay, overlays[1] = ScaleBarOverlay
                    val fixedOverlays = mv.overlays.take(2).toMutableList()
                    mv.overlays.clear()
                    mv.overlays.addAll(fixedOverlays)

                    val pinDrawable = if (mapPinStyle == "default") null
                    else createPinDrawable(
                        style      = mapPinStyle,
                        fillArgb   = primaryArgb,
                        strokeArgb = onPrimaryArgb,
                        sizePx     = (mv.resources.displayMetrics.density * 36).toInt(),
                        resources  = mv.resources
                    )

                    locationGroups.forEach { group ->
                        val pt = GeoPoint(
                            group.representativeRecord.latitude,
                            group.representativeRecord.longitude
                        )
                        val marker = Marker(mv).apply {
                            position = pt
                            title    = group.locationId
                            snippet  = group.address
                            setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
                            isDraggable = false
                            if (pinDrawable != null) icon = pinDrawable
                            setOnMarkerClickListener { _, _ ->
                                selectedGroup = group
                                mv.controller.animateTo(pt)
                                true
                            }
                        }
                        mv.overlays.add(marker)
                    }

                    // ── 現在記録中のルートをポリラインで表示 ─────────────
                    if (currentRoutePoints.size >= 2) {
                        val geoPoints = currentRoutePoints.map { GeoPoint(it.latitude, it.longitude) }
                        val polyline  = Polyline(mv).apply {
                            setPoints(ArrayList(geoPoints))
                            outlinePaint.color       = errorArgb
                            outlinePaint.strokeWidth = 8f
                            outlinePaint.style       = Paint.Style.STROKE
                            outlinePaint.strokeCap   = Paint.Cap.ROUND
                            outlinePaint.strokeJoin  = Paint.Join.ROUND
                        }
                        mv.overlays.add(polyline)
                        // 最新点マーカー
                        Marker(mv).apply {
                            position = geoPoints.last()
                            title    = "現在地"
                            setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
                            mv.overlays.add(this)
                        }
                    }

                    mv.invalidate()

                    // マーカー全体が収まるようズーム調整
                    if (locationGroups.isNotEmpty()) {
                        val pts = locationGroups.map {
                            GeoPoint(
                                it.representativeRecord.latitude,
                                it.representativeRecord.longitude
                            )
                        }
                        if (pts.size == 1) {
                            mv.controller.setZoom(14.0)
                            mv.controller.setCenter(pts.first())
                        } else {
                            mv.post {
                                val bbox = BoundingBox.fromGeoPoints(ArrayList(pts))
                                mv.zoomToBoundingBox(bbox.increaseByScale(1.3f), false)
                            }
                        }
                    }
                },
                modifier = Modifier.fillMaxSize()
            )
        }

        // ── 帰属表示（タイルプロバイダー）────────────────────────────────
        Text(
            text  = tileAttribution(mapTileSource),
            style = MaterialTheme.typography.labelSmall.copy(fontSize = androidx.compose.ui.unit.TextUnit(9f, androidx.compose.ui.unit.TextUnitType.Sp)),
            color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
            modifier = Modifier
                .align(Alignment.BottomStart)
                .padding(start = 4.dp, bottom = 4.dp)
        )

        // ── データなし表示 ────────────────────────────────────────────────
        if (locationGroups.isEmpty()) {
            Card(
                modifier = Modifier
                    .align(Alignment.Center)
                    .padding(24.dp)
            ) {
                Column(
                    modifier = Modifier.padding(24.dp),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    Text(
                        "採集地点がありません",
                        style = MaterialTheme.typography.titleMedium
                    )
                    Text(
                        "採集データを登録するとマップに表示されます",
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.outline
                    )
                }
            }
        }

        // ── 地点情報ポップアップ（マーカータップで表示） ──────────────────
        AnimatedVisibility(
            visible  = selectedGroup != null,
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .onSizeChanged { size -> popupHeightPx = size.height },
            enter    = slideInVertically(initialOffsetY = { it }),
            exit     = slideOutVertically(targetOffsetY = { it })
        ) {
            val group = selectedGroup
            if (group != null) {
                LocationInfoCard(
                    group              = group,
                    thumbnailPhoto     = firstPhotoByLocation[group.locationId],
                    onClose            = { selectedGroup = null },
                    onNavigateToDetail = {
                        selectedGroup = null
                        onNavigateToDetail(group.locationId)
                    }
                )
            }
        }

        // ── ルートログ一覧ボタン（右上） ─────────────────────────────────
        FloatingActionButton(
            onClick           = onNavigateToRouteLogList,
            modifier          = Modifier
                .align(Alignment.TopEnd)
                .padding(top = 12.dp, end = 12.dp)
                .size(44.dp),
            containerColor    = MaterialTheme.colorScheme.surface,
            contentColor      = MaterialTheme.colorScheme.onSurface,
            elevation         = FloatingActionButtonDefaults.elevation(4.dp)
        ) {
            Icon(Icons.Default.List, contentDescription = "ルートログ一覧", modifier = Modifier.size(20.dp))
        }

        // ── 記録開始 / 停止 FAB（右下） ──────────────────────────────────
        // ポップアップが表示されたとき fabBottomPadding がアニメーションで増加し、
        // FAB がポップアップの上にスライドアップする
        FloatingActionButton(
            onClick        = {
                if (isRecording) {
                    routeLogViewModel.stopRecording()
                } else {
                    routeNameInput  = routeLogViewModel.run {
                        val fmt = java.time.format.DateTimeFormatter.ofPattern("MM/dd HH:mm")
                        "ルート ${java.time.LocalDateTime.now().format(fmt)}"
                    }
                    showStartDialog = true
                }
            },
            modifier       = Modifier
                .align(Alignment.BottomEnd)
                .padding(end = 12.dp, bottom = fabBottomPadding),
            containerColor = if (isRecording) MaterialTheme.colorScheme.error
                             else MaterialTheme.colorScheme.primary,
            contentColor   = if (isRecording) MaterialTheme.colorScheme.onError
                             else MaterialTheme.colorScheme.onPrimary
        ) {
            if (isRecording) {
                Icon(Icons.Default.Stop, contentDescription = "記録停止")
            } else {
                Icon(Icons.Default.FiberManualRecord, contentDescription = "記録開始")
            }
        }

        // 記録中バッジ
        if (isRecording) {
            Surface(
                modifier = Modifier
                    .align(Alignment.TopStart)
                    .padding(12.dp),
                color  = MaterialTheme.colorScheme.error,
                shape  = RoundedCornerShape(20.dp)
            ) {
                Row(
                    modifier              = Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
                    verticalAlignment     = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(4.dp)
                ) {
                    Icon(Icons.Default.FiberManualRecord, null,
                         modifier = Modifier.size(10.dp),
                         tint     = MaterialTheme.colorScheme.onError)
                    Text(
                        "記録中  ${currentRoutePoints.size} 点",
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.onError
                    )
                }
            }
        }
    }

    // ── 記録開始ダイアログ ────────────────────────────────────────────────────
    if (showStartDialog) {
        AlertDialog(
            onDismissRequest = { showStartDialog = false },
            title = { Text("経路記録を開始") },
            text  = {
                Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                    Text("ルート名（省略可）")
                    OutlinedTextField(
                        value         = routeNameInput,
                        onValueChange = { routeNameInput = it },
                        placeholder   = { Text("例：調査地A〜B") },
                        singleLine    = true,
                        modifier      = Modifier.fillMaxWidth()
                    )
                    Text(
                        "記録中はGPSが継続して使用されます。バッテリー消費にご注意ください。",
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.outline
                    )
                }
            },
            confirmButton = {
                Button(onClick = {
                    routeLogViewModel.startRecording(
                        routeNameInput.trim().ifBlank {
                            val fmt = java.time.format.DateTimeFormatter.ofPattern("MM/dd HH:mm")
                            "ルート ${java.time.LocalDateTime.now().format(fmt)}"
                        }
                    )
                    showStartDialog = false
                }) { Text("開始") }
            },
            dismissButton = {
                TextButton(onClick = { showStartDialog = false }) { Text("キャンセル") }
            }
        )
    }
}

// ── 地点情報カード ────────────────────────────────────────────────────────────

@Composable
private fun LocationInfoCard(
    group:              MapLocationGroup,
    thumbnailPhoto:     SpecimenPhoto?,
    onClose:            () -> Unit,
    onNavigateToDetail: () -> Unit
) {
    Card(
        modifier  = Modifier
            .fillMaxWidth()
            .padding(start = 12.dp, end = 12.dp, bottom = 12.dp)
            .clickable(onClick = onNavigateToDetail),
        elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
        shape     = RoundedCornerShape(16.dp)
    ) {
        // 高さは最大 110dp に固定してカードが画面を占領しないようにする
        Row(
            modifier          = Modifier
                .fillMaxWidth()
                .heightIn(max = 110.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            // ── 代表写真サムネイル（正方形・固定サイズ） ─────────────
            if (thumbnailPhoto != null && thumbnailPhoto.isPhoto) {
                AsyncImage(
                    model              = File(thumbnailPhoto.filePath),
                    contentDescription = "代表写真",
                    contentScale       = ContentScale.Crop,
                    modifier           = Modifier
                        .size(110.dp)           // 高さに合わせた正方形
                        .clip(RoundedCornerShape(topStart = 16.dp, bottomStart = 16.dp))
                )
            }

            // ── テキスト情報 ──────────────────────────────────────────
            Column(
                modifier = Modifier
                    .weight(1f)
                    .padding(horizontal = 12.dp, vertical = 8.dp),
                verticalArrangement = Arrangement.spacedBy(3.dp)
            ) {
                // ヘッダー行：地点 ID + 閉じるボタン
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(
                        text       = group.locationId,
                        style      = MaterialTheme.typography.titleSmall,
                        fontFamily = FontFamily.Monospace,
                        modifier   = Modifier.weight(1f)
                    )
                    IconButton(
                        onClick  = onClose,
                        modifier = Modifier.size(28.dp)
                    ) {
                        Icon(
                            Icons.Default.Close, "閉じる",
                            modifier = Modifier.size(16.dp),
                            tint     = MaterialTheme.colorScheme.outline
                        )
                    }
                }

                // 住所（1行）
                Text(
                    text     = group.address,
                    style    = MaterialTheme.typography.bodySmall,
                    maxLines = 1,
                    overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
                )

                // 採集日・標本数
                Text(
                    text  = "${group.date}　標本 ${group.specimens.size} 点",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.outline
                )

                // 標高 or GPS（どちらか1行）
                val locLine = if (group.altitude != null) {
                    "標高 ${"%.0f".format(group.altitude)} m　" +
                    "${"%.4f".format(group.representativeRecord.latitude)}°N  " +
                    "${"%.4f".format(group.representativeRecord.longitude)}°E"
                } else {
                    "${"%.5f".format(group.representativeRecord.latitude)}°N  " +
                    "${"%.5f".format(group.representativeRecord.longitude)}°E"
                }
                Text(
                    text     = locLine,
                    style    = MaterialTheme.typography.labelSmall.copy(fontFamily = FontFamily.Monospace),
                    color    = MaterialTheme.colorScheme.outline,
                    maxLines = 1,
                    overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
                )

                // タップ誘導
                Row(
                    verticalAlignment     = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.End,
                    modifier              = Modifier.fillMaxWidth()
                ) {
                    Text(
                        "詳細を見る",
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.primary
                    )
                    Icon(
                        Icons.Default.OpenInNew, null,
                        modifier = Modifier.size(12.dp),
                        tint     = MaterialTheme.colorScheme.primary
                    )
                }
            }
        }
    }
}
