package com.fieldlabel.collector.data

import android.location.Location
import com.fieldlabel.collector.data.local.RouteLogDao
import com.fieldlabel.collector.data.local.RouteLogEntity
import com.fieldlabel.collector.data.local.RoutePointDao
import com.fieldlabel.collector.data.local.RoutePointEntity
import com.fieldlabel.collector.domain.model.RouteLog
import com.fieldlabel.collector.domain.model.RoutePoint
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class RouteLogRepository @Inject constructor(
    private val routeLogDao: RouteLogDao,
    private val routePointDao: RoutePointDao
) {
    // ── 全ログの Flow（降順） ────────────────────────────────────────────────
    val allRouteLogs: Flow<List<RouteLog>> =
        routeLogDao.getAllFlow().map { list -> list.map { it.toDomain() } }

    // ── ログ開始 ─────────────────────────────────────────────────────────────
    /**
     * 新しいルートログを作成して ID を返す。
     */
    suspend fun startNewLog(name: String): String {
        val id = UUID.randomUUID().toString()
        routeLogDao.insert(
            RouteLogEntity(
                id                  = id,
                name                = name,
                startTime           = System.currentTimeMillis(),
                endTime             = null,
                totalDistanceMeters = 0.0,
                pointCount          = 0
            )
        )
        return id
    }

    // ── 測位点追加 ───────────────────────────────────────────────────────────
    suspend fun addPoint(routeLogId: String, point: RoutePoint) {
        routePointDao.insert(RoutePointEntity.fromDomain(point))
    }

    // ── ログ終了 ─────────────────────────────────────────────────────────────
    /**
     * ログを終了し、合計距離とポイント数を確定する。
     */
    suspend fun finishLog(routeLogId: String) {
        val points   = routePointDao.getByRouteLogId(routeLogId)
        val distance = calculateTotalDistance(points)
        routeLogDao.finishLog(
            id       = routeLogId,
            endTime  = System.currentTimeMillis(),
            distance = distance,
            count    = points.size
        )
    }

    // ── 測位点取得 ───────────────────────────────────────────────────────────
    suspend fun getPoints(routeLogId: String): List<RoutePoint> =
        routePointDao.getByRouteLogId(routeLogId).map { it.toDomain() }

    fun getPointsFlow(routeLogId: String): Flow<List<RoutePoint>> =
        routePointDao.getByRouteLogIdFlow(routeLogId).map { list -> list.map { it.toDomain() } }

    // ── 削除 ─────────────────────────────────────────────────────────────────
    suspend fun deleteLog(routeLogId: String) {
        routePointDao.deleteByRouteLogId(routeLogId)
        routeLogDao.deleteById(routeLogId)
    }

    // ── インポート用一括挿入 ──────────────────────────────────────────────────
    /**
     * インポート時に既存ログ + 測位点をそのまま挿入する。
     */
    suspend fun importLog(log: RouteLog, points: List<RoutePoint>) {
        routeLogDao.insert(RouteLogEntity.fromDomain(log))
        points.forEach { routePointDao.insert(RoutePointEntity.fromDomain(it)) }
    }

    // ── エクスポート用一括取得 ────────────────────────────────────────────────
    suspend fun getAllLogsOnce(): List<RouteLog>  =
        routeLogDao.getAllOnce().map { it.toDomain() }

    suspend fun getAllPointsOnce(): List<RoutePoint> =
        routePointDao.getAllOnce().map { it.toDomain() }

    // ── 距離計算（Haversine近似 / Android Location API） ─────────────────────
    private fun calculateTotalDistance(points: List<RoutePointEntity>): Double {
        if (points.size < 2) return 0.0
        val results = FloatArray(1)
        var total   = 0.0
        for (i in 1 until points.size) {
            Location.distanceBetween(
                points[i - 1].latitude, points[i - 1].longitude,
                points[i].latitude,     points[i].longitude,
                results
            )
            total += results[0]
        }
        return total
    }
}
