package com.fieldlabel.collector.ui.screens

import android.content.Intent
import android.media.MediaMetadataRetriever
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
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.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.core.content.FileProvider
import androidx.hilt.navigation.compose.hiltViewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.fieldlabel.collector.domain.model.CollectionRecord
import com.fieldlabel.collector.domain.model.SpecimenPhoto
import com.fieldlabel.collector.service.ExportState
import com.fieldlabel.collector.ui.viewmodel.BatchPrintState
import com.fieldlabel.collector.ui.viewmodel.LocationDetailViewModel
import java.io.File
import androidx.compose.runtime.saveable.rememberSaveable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

// ─────────────────────────────────────────────────────────────────────────────
// LocationDetailScreen
// ─────────────────────────────────────────────────────────────────────────────

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LocationDetailScreen(
    onNavigateBack:          () -> Unit,
    onNavigateToPreview:     (String) -> Unit,
    onNavigateToMediaPreview: (filePath: String, mediaType: String, locationId: String, specimenId: String?) -> Unit = { _, _, _, _ -> },
    viewModel: LocationDetailViewModel = hiltViewModel()
) {
    val context         = LocalContext.current
    val specimens       by viewModel.specimens.collectAsState()
    val photos          by viewModel.photos.collectAsState()
    val exportState     by viewModel.exportState.collectAsState()
    val batchPrintState by viewModel.batchPrintState.collectAsState()

    var selectedTab      by rememberSaveable { mutableStateOf(0) }
    var showExportDialog by remember { mutableStateOf(false) }

    // 一括印刷結果ダイアログ
    when (val bp = batchPrintState) {
        is BatchPrintState.Done -> AlertDialog(
            onDismissRequest = { viewModel.clearBatchPrintState() },
            icon  = { Icon(Icons.Default.Print, null) },
            title = { Text("印刷完了") },
            text  = { Text(bp.message) },
            confirmButton = {
                TextButton(onClick = { viewModel.clearBatchPrintState() }) { Text("OK") }
            }
        )
        is BatchPrintState.Error -> AlertDialog(
            onDismissRequest = { viewModel.clearBatchPrintState() },
            title = { Text("印刷エラー") },
            text  = { Text(bp.message) },
            confirmButton = {
                TextButton(onClick = { viewModel.clearBatchPrintState() }) { Text("閉じる") }
            }
        )
        else -> {}
    }

    // エクスポート完了時に共有インテントを発行
    LaunchedEffect(exportState) {
        if (exportState is ExportState.Done) {
            val file = (exportState as ExportState.Done).file
            val uri  = FileProvider.getUriForFile(
                context,
                "${context.packageName}.fileprovider",
                file
            )
            val mimeType = if (file.name.endsWith(".zip"))
                "application/zip"
            else
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

            val intent = Intent(Intent.ACTION_SEND).apply {
                type    = mimeType
                putExtra(Intent.EXTRA_STREAM, uri)
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }
            context.startActivity(Intent.createChooser(intent, "エクスポートファイルを共有"))
            viewModel.clearExportState()
        }
    }

    // ── エクスポートオプションダイアログ ──────────────────────────────────────
    if (showExportDialog) {
        ExportDialog(
            locationId = viewModel.locationId,
            hasPhotos  = photos.isNotEmpty(),
            onExport   = { includePhotos ->
                showExportDialog = false
                viewModel.exportLocation(includePhotos)
            },
            onDismiss  = { showExportDialog = false }
        )
    }

    // ── エラーダイアログ ──────────────────────────────────────────────────────
    if (exportState is ExportState.Error) {
        AlertDialog(
            onDismissRequest = { viewModel.clearExportState() },
            title = { Text("エクスポートエラー") },
            text  = { Text((exportState as ExportState.Error).message) },
            confirmButton = {
                TextButton(onClick = { viewModel.clearExportState() }) { Text("閉じる") }
            }
        )
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Column {
                        Text(
                            viewModel.locationId,
                            style = MaterialTheme.typography.titleMedium.copy(
                                fontFamily = FontFamily.Monospace,
                                fontWeight = FontWeight.Bold
                            )
                        )
                        if (specimens.isNotEmpty()) {
                            val rep = specimens.first()
                            val dates = specimens.map { it.collectionDate }.distinct().sorted()
                            val dateLabel = if (dates.size > 1)
                                "${dates.first()}〜${dates.last()}"
                            else
                                dates.first().toString()
                            Text(
                                "$dateLabel  ·  ${rep.collectorName}",
                                style = MaterialTheme.typography.bodySmall,
                                color = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                        }
                    }
                },
                navigationIcon = {
                    IconButton(onClick = onNavigateBack) {
                        Icon(Icons.Default.ArrowBack, contentDescription = "戻る")
                    }
                },
                actions = {
                    // 一括印刷ボタン
                    if (batchPrintState is BatchPrintState.Printing) {
                        Box(
                            modifier = Modifier.size(48.dp),
                            contentAlignment = Alignment.Center
                        ) {
                            CircularProgressIndicator(modifier = Modifier.size(24.dp))
                        }
                    } else {
                        IconButton(
                            onClick  = { viewModel.printAllSpecimens() },
                            enabled  = specimens.isNotEmpty()
                        ) {
                            Icon(Icons.Default.Print, contentDescription = "標本を一括印刷")
                        }
                    }
                    // エクスポートボタン
                    if (exportState is ExportState.InProgress) {
                        Box(
                            modifier = Modifier.size(48.dp),
                            contentAlignment = Alignment.Center
                        ) {
                            CircularProgressIndicator(modifier = Modifier.size(24.dp))
                        }
                    } else {
                        IconButton(onClick = { showExportDialog = true }) {
                            Icon(Icons.Default.FileDownload, contentDescription = "エクスポート")
                        }
                    }
                }
            )
        }
    ) { innerPadding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding)
        ) {
            // ── タブバー ───────────────────────────────────────────────────
            TabRow(selectedTabIndex = selectedTab) {
                Tab(
                    selected = selectedTab == 0,
                    onClick  = { selectedTab = 0 },
                    text = {
                        Text("標本一覧 (${specimens.size})")
                    },
                    icon = { Icon(Icons.Default.Science, null, modifier = Modifier.size(16.dp)) }
                )
                Tab(
                    selected = selectedTab == 1,
                    onClick  = { selectedTab = 1 },
                    text = {
                        Text("メディア一覧 (${photos.size})")
                    },
                    icon = { Icon(Icons.Default.PermMedia, null, modifier = Modifier.size(16.dp)) }
                )
            }

            // ── タブコンテンツ ─────────────────────────────────────────────
            when (selectedTab) {
                0 -> SpecimenTab(
                    specimens            = specimens,
                    onNavigateToPreview  = onNavigateToPreview,
                    onDelete             = { viewModel.deleteRecord(it) },
                    onUpdate             = { viewModel.updateRecord(it) }
                )
                1 -> PhotoTab(
                    photos                   = photos,
                    specimens                = specimens,
                    onDelete                 = { viewModel.deletePhoto(it) },
                    onNavigateToMediaPreview = onNavigateToMediaPreview,
                )
            }
        }
    }
}

// ─────────────────────────────────────────────────────────────────────────────
// 標本タブ
// ─────────────────────────────────────────────────────────────────────────────

@Composable
private fun SpecimenTab(
    specimens:           List<CollectionRecord>,
    onNavigateToPreview: (String) -> Unit,
    onDelete:            (CollectionRecord) -> Unit,
    onUpdate:            (CollectionRecord) -> Unit
) {
    if (specimens.isEmpty()) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Text(
                "標本データがありません",
                style = MaterialTheme.typography.bodyLarge,
                color = MaterialTheme.colorScheme.outline
            )
        }
        return
    }

    // 地点情報ヘッダー
    val rep = specimens.first()

    LazyColumn(
        contentPadding      = PaddingValues(12.dp),
        verticalArrangement = Arrangement.spacedBy(6.dp),
        modifier            = Modifier.fillMaxSize()
    ) {
        // 地点情報サマリー
        item {
            LocationInfoCard(specimens = specimens)
        }
        item {
            Text(
                "標本 ${specimens.size} 点",
                style    = MaterialTheme.typography.labelMedium,
                color    = MaterialTheme.colorScheme.outline,
                modifier = Modifier.padding(vertical = 4.dp)
            )
        }
        items(specimens, key = { it.id }) { specimen ->
            DetailSpecimenRow(
                record    = specimen,
                onPreview = { onNavigateToPreview(specimen.id) },
                onDelete  = { onDelete(specimen) },
                onUpdate  = { onUpdate(it) }
            )
        }
    }
}

@Composable
private fun LocationInfoCard(specimens: List<CollectionRecord>) {
    val rep = specimens.first()

    // 採集日：複数日にまたがる場合は範囲表示
    val dateLabel = run {
        val dates = specimens.map { it.collectionDate }.distinct().sorted()
        if (dates.size > 1) "${dates.first()}〜${dates.last()}" else dates.first().toString()
    }

    Card(
        modifier = Modifier.fillMaxWidth(),
        colors   = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.4f)
        )
    ) {
        Column(
            modifier            = Modifier.padding(12.dp),
            verticalArrangement = Arrangement.spacedBy(4.dp)
        ) {
            // 採集日・採集者
            Row(
                verticalAlignment     = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                Icon(
                    Icons.Default.CalendarToday,
                    null,
                    modifier = Modifier.size(14.dp),
                    tint     = MaterialTheme.colorScheme.primary
                )
                Text(
                    dateLabel,
                    style      = MaterialTheme.typography.bodyMedium,
                    fontWeight = FontWeight.SemiBold
                )
                Text(
                    "·  ${rep.collectorName}",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
            }

            // 住所
            if (!rep.address.isNullOrBlank()) {
                Row(
                    verticalAlignment     = Alignment.Top,
                    horizontalArrangement = Arrangement.spacedBy(6.dp)
                ) {
                    Icon(
                        Icons.Default.LocationOn,
                        null,
                        modifier = Modifier.padding(top = 2.dp).size(14.dp),
                        tint     = MaterialTheme.colorScheme.primary
                    )
                    Text(rep.address!!, style = MaterialTheme.typography.bodySmall)
                }
            }

            // 座標・標高チップ
            Row(
                verticalAlignment     = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(16.dp)
            ) {
                CoordChip(label = "緯度", value = "%.6f".format(rep.latitude))
                CoordChip(label = "経度", value = "%.6f".format(rep.longitude))
                rep.altitude?.let { alt ->
                    CoordChip(label = "標高", value = "%.0fm".format(alt))
                }
            }
        }
    }
}

@Composable
private fun CoordChip(label: String, value: String) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(
            label,
            style = MaterialTheme.typography.labelSmall,
            color = MaterialTheme.colorScheme.outline
        )
        Text(
            value,
            style      = MaterialTheme.typography.bodySmall.copy(fontFamily = FontFamily.Monospace),
            fontWeight = FontWeight.Medium
        )
    }
}

@Composable
private fun DetailSpecimenRow(
    record:    CollectionRecord,
    onPreview: () -> Unit,
    onDelete:  () -> Unit,
    onUpdate:  (CollectionRecord) -> Unit
) {
    var showEditDialog   by remember { mutableStateOf(false) }
    var showDeleteDialog by remember { mutableStateOf(false) }

    if (showEditDialog) {
        DetailEditSpecimenDialog(
            record    = record,
            onSave    = { updated -> onUpdate(updated); showEditDialog = false },
            onDismiss = { showEditDialog = false }
        )
    }
    if (showDeleteDialog) {
        AlertDialog(
            onDismissRequest = { showDeleteDialog = false },
            title  = { Text("標本の削除") },
            text   = { Text("${record.specimenId} を削除しますか？\nこの操作は元に戻せません。") },
            confirmButton = {
                TextButton(
                    onClick = { onDelete(); showDeleteDialog = false },
                    colors  = ButtonDefaults.textButtonColors(
                        contentColor = MaterialTheme.colorScheme.error
                    )
                ) { Text("削除") }
            },
            dismissButton = {
                TextButton(onClick = { showDeleteDialog = false }) { Text("キャンセル") }
            }
        )
    }

    Surface(
        shape    = MaterialTheme.shapes.small,
        color    = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f),
        modifier = Modifier.fillMaxWidth()
    ) {
        Row(
            modifier          = Modifier.padding(start = 12.dp, top = 6.dp, bottom = 6.dp, end = 4.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Column(modifier = Modifier.weight(1f)) {
                Row(
                    verticalAlignment     = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(6.dp)
                ) {
                    Text(
                        record.specimenId,
                        style = MaterialTheme.typography.bodyMedium.copy(
                            fontFamily = FontFamily.Monospace,
                            fontWeight = FontWeight.SemiBold
                        )
                    )
                    if (record.synced) {
                        Icon(Icons.Default.CloudDone, "同期済み",
                            modifier = Modifier.size(13.dp),
                            tint     = MaterialTheme.colorScheme.primary)
                    } else {
                        Icon(Icons.Default.CloudOff, "未同期",
                            modifier = Modifier.size(13.dp),
                            tint     = MaterialTheme.colorScheme.outline)
                    }
                }
                // 採集日（標本ごとに異なる可能性があるので個別表示）
                Text(
                    record.collectionDate.toString(),
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.outline
                )
                if (record.notes.isNotBlank()) {
                    Text(
                        record.notes,
                        style    = MaterialTheme.typography.bodySmall,
                        color    = MaterialTheme.colorScheme.outline,
                        maxLines = 2,
                        overflow = TextOverflow.Ellipsis
                    )
                }
            }
            IconButton(onClick = onPreview, modifier = Modifier.size(36.dp)) {
                Icon(Icons.Default.Visibility, "プレビュー", modifier = Modifier.size(18.dp))
            }
            IconButton(onClick = { showEditDialog = true }, modifier = Modifier.size(36.dp)) {
                Icon(Icons.Default.Edit, "編集", modifier = Modifier.size(18.dp))
            }
            IconButton(
                onClick  = { showDeleteDialog = true },
                modifier = Modifier.size(36.dp),
                colors   = IconButtonDefaults.iconButtonColors(
                    contentColor = MaterialTheme.colorScheme.error
                )
            ) {
                Icon(Icons.Default.Delete, "削除", modifier = Modifier.size(18.dp))
            }
        }
    }
}

@Composable
private fun DetailEditSpecimenDialog(
    record:    CollectionRecord,
    onSave:    (CollectionRecord) -> Unit,
    onDismiss: () -> Unit
) {
    var notes         by remember { mutableStateOf(record.notes) }
    var collectorName by remember { mutableStateOf(record.collectorName) }

    AlertDialog(
        onDismissRequest = onDismiss,
        title  = { Text("標本を編集: ${record.specimenId}") },
        text   = {
            Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                OutlinedTextField(
                    value         = collectorName,
                    onValueChange = { collectorName = it },
                    label         = { Text("採集者名") },
                    leadingIcon   = { Icon(Icons.Default.Person, null) },
                    singleLine    = true,
                    modifier      = Modifier.fillMaxWidth()
                )
                OutlinedTextField(
                    value         = notes,
                    onValueChange = { notes = it },
                    label         = { Text("備考・メモ") },
                    leadingIcon   = { Icon(Icons.Default.Notes, null) },
                    minLines      = 2,
                    maxLines      = 4,
                    modifier      = Modifier.fillMaxWidth()
                )
            }
        },
        confirmButton = {
            TextButton(
                onClick = { onSave(record.copy(notes = notes, collectorName = collectorName)) },
                enabled = collectorName.isNotBlank()
            ) { Text("保存") }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) { Text("キャンセル") }
        }
    )
}

// ─────────────────────────────────────────────────────────────────────────────
// 写真タブ
// ─────────────────────────────────────────────────────────────────────────────

@Composable
private fun PhotoTab(
    photos:                   List<SpecimenPhoto>,
    specimens:                List<CollectionRecord>,
    onDelete:                 (SpecimenPhoto) -> Unit,
    onNavigateToMediaPreview: (filePath: String, mediaType: String, locationId: String, specimenId: String?) -> Unit = { _, _, _, _ -> }
) {
    // プレビュー対象の写真（削除確認ダイアログ用に保持）
    var previewPhoto by remember { mutableStateOf<SpecimenPhoto?>(null) }

    // 写真プレビューダイアログ（photo のみ、video/audio は MediaPreviewScreen へ）
    previewPhoto?.let { photo ->
        if (photo.isPhoto) {
            PhotoPreviewDialog(
                photo     = photo,
                specimens = specimens,
                onDismiss = { previewPhoto = null },
                onDelete  = {
                    onDelete(photo)
                    previewPhoto = null
                }
            )
        }
    }

    if (photos.isEmpty()) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Column(
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                Icon(
                    Icons.Default.PermMedia,
                    null,
                    modifier = Modifier.size(48.dp),
                    tint     = MaterialTheme.colorScheme.outline
                )
                Text(
                    "メディアがありません",
                    style = MaterialTheme.typography.bodyLarge,
                    color = MaterialTheme.colorScheme.outline
                )
            }
        }
        return
    }

    LazyVerticalGrid(
        columns               = GridCells.Fixed(3),
        contentPadding        = PaddingValues(4.dp),
        verticalArrangement   = Arrangement.spacedBy(4.dp),
        horizontalArrangement = Arrangement.spacedBy(4.dp),
        modifier              = Modifier.fillMaxSize()
    ) {
        items(photos, key = { it.id }) { photo ->
            PhotoGridItem(
                photo     = photo,
                onTap     = {
                    if (photo.isPhoto) {
                        previewPhoto = photo
                    } else {
                        onNavigateToMediaPreview(photo.filePath, photo.mediaType, photo.locationId, photo.specimenId)
                    }
                },
                onDelete  = { onDelete(photo) }
            )
        }
    }
}

@Composable
private fun PhotoGridItem(
    photo:    SpecimenPhoto,
    onTap:    () -> Unit,
    onDelete: () -> Unit
) {
    var showDeleteDialog by remember { mutableStateOf(false) }

    // 動画サムネイルを非同期で取得
    var videoThumbnail by remember(photo.filePath) { mutableStateOf<android.graphics.Bitmap?>(null) }
    LaunchedEffect(photo.filePath) {
        if (photo.isVideo) {
            videoThumbnail = withContext(Dispatchers.IO) {
                try {
                    val retriever = MediaMetadataRetriever()
                    retriever.setDataSource(photo.filePath)
                    val frame = retriever.getFrameAtTime(0L, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
                    retriever.release()
                    frame
                } catch (_: Exception) { null }
            }
        }
    }

    if (showDeleteDialog) {
        AlertDialog(
            onDismissRequest = { showDeleteDialog = false },
            title  = { Text("メディアを削除") },
            text   = { Text("このメディアを削除しますか？\n元に戻すことはできません。") },
            confirmButton = {
                TextButton(
                    onClick = { onDelete(); showDeleteDialog = false },
                    colors  = ButtonDefaults.textButtonColors(
                        contentColor = MaterialTheme.colorScheme.error
                    )
                ) { Text("削除") }
            },
            dismissButton = {
                TextButton(onClick = { showDeleteDialog = false }) { Text("キャンセル") }
            }
        )
    }

    Box(
        modifier = Modifier
            .aspectRatio(1f)
            .clip(RoundedCornerShape(4.dp))
            .background(MaterialTheme.colorScheme.surfaceVariant)
            .clickable(onClick = onTap)
    ) {
        val context = LocalContext.current
        if (photo.isPhoto) {
            AsyncImage(
                model = ImageRequest.Builder(context)
                    .data(File(photo.filePath))
                    .crossfade(true)
                    .build(),
                contentDescription = photo.specimenId?.let { "標本 $it の写真" } ?: "地点写真",
                contentScale = ContentScale.Crop,
                modifier     = Modifier.fillMaxSize()
            )
        } else if (photo.isVideo) {
            // 動画: サムネイル表示 + 再生アイコンオーバーレイ
            if (videoThumbnail != null) {
                Image(
                    bitmap             = videoThumbnail!!.asImageBitmap(),
                    contentDescription = "動画",
                    contentScale       = ContentScale.Crop,
                    modifier           = Modifier.fillMaxSize()
                )
            } else {
                Box(
                    modifier         = Modifier.fillMaxSize(),
                    contentAlignment = Alignment.Center
                ) {
                    Icon(
                        imageVector        = Icons.Default.Videocam,
                        contentDescription = "動画",
                        modifier           = Modifier.size(40.dp),
                        tint               = MaterialTheme.colorScheme.onSurfaceVariant
                    )
                }
            }
            // 再生ボタンオーバーレイ（常に表示）
            Box(
                modifier         = Modifier.fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                Icon(
                    imageVector        = Icons.Default.PlayCircle,
                    contentDescription = null,
                    modifier           = Modifier.size(36.dp),
                    tint               = Color.White.copy(alpha = 0.85f)
                )
            }
        } else {
            // 音声: マイクアイコン
            Box(
                modifier         = Modifier.fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                Icon(
                    imageVector        = Icons.Default.Mic,
                    contentDescription = "音声",
                    modifier           = Modifier.size(40.dp),
                    tint               = MaterialTheme.colorScheme.onSurfaceVariant
                )
            }
        }

        // 標本ID タグ（写真に紐づいている場合）
        if (!photo.specimenId.isNullOrBlank()) {
            Surface(
                modifier = Modifier
                    .align(Alignment.BottomStart)
                    .padding(3.dp),
                shape = RoundedCornerShape(2.dp),
                color = Color.Black.copy(alpha = 0.65f)
            ) {
                Text(
                    photo.specimenId!!,
                    style    = MaterialTheme.typography.labelSmall.copy(
                        fontFamily = FontFamily.Monospace
                    ),
                    color    = Color.White,
                    modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
            }
        }

        // 削除ボタン
        IconButton(
            onClick  = { showDeleteDialog = true },
            modifier = Modifier
                .align(Alignment.TopEnd)
                .size(32.dp)
        ) {
            Surface(
                shape = RoundedCornerShape(50),
                color = Color.Black.copy(alpha = 0.55f)
            ) {
                Icon(
                    Icons.Default.Delete,
                    contentDescription = "削除",
                    modifier = Modifier
                        .padding(4.dp)
                        .size(16.dp),
                    tint = Color.White
                )
            }
        }
    }
}

// ─────────────────────────────────────────────────────────────────────────────
// 写真フルスクリーンプレビューダイアログ
// ─────────────────────────────────────────────────────────────────────────────

@Composable
private fun PhotoPreviewDialog(
    photo:     SpecimenPhoto,
    specimens: List<CollectionRecord>,
    onDismiss: () -> Unit,
    onDelete:  () -> Unit
) {
    // ピンチズーム用状態
    var scale       by remember { mutableStateOf(1f) }
    var offsetX     by remember { mutableStateOf(0f) }
    var offsetY     by remember { mutableStateOf(0f) }
    var showDeleteDialog by remember { mutableStateOf(false) }

    // 紐づいている標本情報
    val linkedSpecimen = remember(photo.specimenId, specimens) {
        photo.specimenId?.let { sid -> specimens.find { it.specimenId == sid } }
    }

    if (showDeleteDialog) {
        AlertDialog(
            onDismissRequest = { showDeleteDialog = false },
            title  = { Text("写真を削除") },
            text   = { Text("この写真を削除しますか？\n元に戻すことはできません。") },
            confirmButton = {
                TextButton(
                    onClick = { onDelete(); showDeleteDialog = false },
                    colors  = ButtonDefaults.textButtonColors(
                        contentColor = MaterialTheme.colorScheme.error
                    )
                ) { Text("削除") }
            },
            dismissButton = {
                TextButton(onClick = { showDeleteDialog = false }) { Text("キャンセル") }
            }
        )
    }

    Dialog(
        onDismissRequest = onDismiss,
        properties = DialogProperties(
            usePlatformDefaultWidth = false,
            dismissOnClickOutside   = true
        )
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
            val context = LocalContext.current

            // ── 写真（ピンチズーム対応） ───────────────────────────────────
            AsyncImage(
                model = ImageRequest.Builder(context)
                    .data(File(photo.filePath))
                    .crossfade(false)
                    .build(),
                contentDescription = "写真プレビュー",
                contentScale = ContentScale.Fit,
                modifier     = Modifier
                    .fillMaxSize()
                    .pointerInput(Unit) {
                        detectTransformGestures { _, pan, zoom, _ ->
                            scale = (scale * zoom).coerceIn(1f, 5f)
                            if (scale > 1f) {
                                offsetX += pan.x
                                offsetY += pan.y
                            } else {
                                offsetX = 0f
                                offsetY = 0f
                            }
                        }
                    }
                    .graphicsLayer(
                        scaleX       = scale,
                        scaleY       = scale,
                        translationX = offsetX,
                        translationY = offsetY
                    )
            )

            // ── 上部ツールバー ────────────────────────────────────────────
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .background(Color.Black.copy(alpha = 0.45f))
                    .statusBarsPadding()
                    .padding(horizontal = 4.dp, vertical = 4.dp),
                verticalAlignment     = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                IconButton(onClick = onDismiss) {
                    Icon(Icons.Default.Close, "閉じる", tint = Color.White)
                }
                // ズームリセット
                if (scale > 1f) {
                    TextButton(onClick = { scale = 1f; offsetX = 0f; offsetY = 0f }) {
                        Text("リセット", color = Color.White)
                    }
                }
                IconButton(onClick = { showDeleteDialog = true }) {
                    Icon(
                        Icons.Default.Delete, "削除",
                        tint = MaterialTheme.colorScheme.error
                    )
                }
            }

            // ── 下部情報オーバーレイ ──────────────────────────────────────
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .align(Alignment.BottomCenter)
                    .background(Color.Black.copy(alpha = 0.6f))
                    .navigationBarsPadding()
                    .padding(horizontal = 16.dp, vertical = 12.dp),
                verticalArrangement = Arrangement.spacedBy(4.dp)
            ) {
                // 写真の種別（地点写真 or 標本写真）
                if (linkedSpecimen != null) {
                    Row(
                        verticalAlignment     = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(6.dp)
                    ) {
                        Icon(
                            Icons.Default.Science, null,
                            modifier = Modifier.size(14.dp),
                            tint     = MaterialTheme.colorScheme.primaryContainer
                        )
                        Text(
                            "標本写真: ${linkedSpecimen.specimenId}",
                            style      = MaterialTheme.typography.labelLarge,
                            color      = Color.White,
                            fontWeight = FontWeight.Bold
                        )
                    }
                    // 備考
                    if (linkedSpecimen.notes.isNotBlank()) {
                        Row(
                            verticalAlignment     = Alignment.Top,
                            horizontalArrangement = Arrangement.spacedBy(6.dp)
                        ) {
                            Icon(
                                Icons.Default.Notes, null,
                                modifier = Modifier.padding(top = 2.dp).size(14.dp),
                                tint     = Color.White.copy(alpha = 0.7f)
                            )
                            Text(
                                linkedSpecimen.notes,
                                style    = MaterialTheme.typography.bodySmall,
                                color    = Color.White.copy(alpha = 0.85f),
                                maxLines = 3,
                                overflow = TextOverflow.Ellipsis
                            )
                        }
                    }
                } else {
                    Row(
                        verticalAlignment     = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(6.dp)
                    ) {
                        Icon(
                            Icons.Default.LocationOn, null,
                            modifier = Modifier.size(14.dp),
                            tint     = MaterialTheme.colorScheme.primaryContainer
                        )
                        Text(
                            "地点写真: ${photo.locationId}",
                            style      = MaterialTheme.typography.labelLarge,
                            color      = Color.White,
                            fontWeight = FontWeight.Bold
                        )
                    }
                }

                // 採集日・採集者
                val rep = linkedSpecimen
                if (rep != null) {
                    Row(
                        horizontalArrangement = Arrangement.spacedBy(12.dp)
                    ) {
                        Text(
                            rep.collectionDate.toString(),
                            style = MaterialTheme.typography.bodySmall,
                            color = Color.White.copy(alpha = 0.7f)
                        )
                        Text(
                            rep.collectorName,
                            style = MaterialTheme.typography.bodySmall,
                            color = Color.White.copy(alpha = 0.7f)
                        )
                    }
                }

                // 地点住所
                val address = linkedSpecimen?.address ?: run {
                    // 地点写真の場合、同じ地点の任意のレコードから住所を取得
                    specimens.firstOrNull()?.address
                }
                if (!address.isNullOrBlank()) {
                    Row(
                        verticalAlignment     = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(6.dp)
                    ) {
                        Icon(
                            Icons.Default.Place, null,
                            modifier = Modifier.size(12.dp),
                            tint     = Color.White.copy(alpha = 0.6f)
                        )
                        Text(
                            address,
                            style    = MaterialTheme.typography.bodySmall,
                            color    = Color.White.copy(alpha = 0.6f),
                            maxLines = 1,
                            overflow = TextOverflow.Ellipsis
                        )
                    }
                }
            }
        }
    }
}

// ─────────────────────────────────────────────────────────────────────────────
// エクスポートダイアログ
// ─────────────────────────────────────────────────────────────────────────────

@Composable
private fun ExportDialog(
    locationId: String,
    hasPhotos:  Boolean,
    onExport:   (includePhotos: Boolean) -> Unit,
    onDismiss:  () -> Unit
) {
    var includePhotos by remember { mutableStateOf(false) }

    AlertDialog(
        onDismissRequest = onDismiss,
        icon  = { Icon(Icons.Default.FileDownload, null) },
        title = { Text("データをエクスポート") },
        text  = {
            Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                Text(
                    "地点 $locationId のデータをエクスポートします。",
                    style = MaterialTheme.typography.bodyMedium
                )

                // 写真を含むかどうかのスイッチ
                if (hasPhotos) {
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        verticalAlignment     = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween
                    ) {
                        Column(modifier = Modifier.weight(1f)) {
                            Text("写真を含める", style = MaterialTheme.typography.bodyMedium)
                            Text(
                                "XLSX + 写真を ZIP にまとめて出力",
                                style = MaterialTheme.typography.bodySmall,
                                color = MaterialTheme.colorScheme.outline
                            )
                        }
                        Switch(
                            checked         = includePhotos,
                            onCheckedChange = { includePhotos = it }
                        )
                    }
                }

                // 出力形式の説明
                Surface(
                    shape = MaterialTheme.shapes.small,
                    color = MaterialTheme.colorScheme.surfaceVariant
                ) {
                    Row(
                        modifier = Modifier.padding(10.dp),
                        horizontalArrangement = Arrangement.spacedBy(8.dp),
                        verticalAlignment     = Alignment.CenterVertically
                    ) {
                        Icon(
                            if (includePhotos && hasPhotos) Icons.Default.FolderZip
                            else Icons.Default.TableChart,
                            null,
                            modifier = Modifier.size(20.dp),
                            tint     = MaterialTheme.colorScheme.primary
                        )
                        Column {
                            Text(
                                if (includePhotos && hasPhotos) "ZIP (Excel + 写真)"
                                else "Excel (.xlsx)",
                                style      = MaterialTheme.typography.bodySmall,
                                fontWeight = FontWeight.SemiBold
                            )
                            Text(
                                if (includePhotos && hasPhotos)
                                    "写真パスはスプレッドシート内の相対パスで記載"
                                else
                                    "標本情報のみをスプレッドシートに出力",
                                style = MaterialTheme.typography.bodySmall,
                                color = MaterialTheme.colorScheme.outline
                            )
                        }
                    }
                }
            }
        },
        confirmButton = {
            Button(onClick = { onExport(includePhotos && hasPhotos) }) {
                Icon(Icons.Default.FileDownload, null)
                Spacer(Modifier.width(6.dp))
                Text("エクスポート")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) { Text("キャンセル") }
        }
    )
}
