package com.fieldlabel.collector.service

import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.Build
import androidx.core.app.NotificationCompat
import com.fieldlabel.collector.MainActivity
import com.fieldlabel.collector.data.RouteLogRepository
import com.fieldlabel.collector.domain.model.RoutePoint
import com.google.android.gms.location.*
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.util.UUID
import javax.inject.Inject

/**
 * 移動経路ロガー。フォアグラウンドサービスとして動作し、
 * FusedLocationProviderClient から定期的に位置情報を取得して
 * RouteLogRepository に書き込む。
 */
@AndroidEntryPoint
class RouteLoggerService : Service() {

    companion object {
        /** 外部からサービスの状態を確認するためのフラグ */
        @Volatile var isRunning: Boolean = false
            private set

        /** 現在記録中のルートログ ID */
        @Volatile var currentRouteLogId: String? = null
            private set

        const val ACTION_START      = "com.fieldlabel.collector.ROUTE_START"
        const val ACTION_STOP       = "com.fieldlabel.collector.ROUTE_STOP"
        const val EXTRA_ROUTE_NAME  = "route_name"

        private const val CHANNEL_ID   = "route_logger_channel"
        private const val NOTIF_ID     = 3001
    }

    @Inject lateinit var routeLogRepository: RouteLogRepository

    private val fusedClient: FusedLocationProviderClient by lazy {
        LocationServices.getFusedLocationProviderClient(this)
    }

    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())

    private var currentLogId: String? = null

    private val locationCallback = object : LocationCallback() {
        override fun onLocationResult(result: LocationResult) {
            val location = result.lastLocation ?: return
            val logId    = currentLogId ?: return
            scope.launch {
                routeLogRepository.addPoint(
                    routeLogId = logId,
                    point = RoutePoint(
                        id         = UUID.randomUUID().toString(),
                        routeLogId = logId,
                        latitude   = location.latitude,
                        longitude  = location.longitude,
                        altitude   = location.altitude,
                        timestamp  = location.time,
                        accuracy   = location.accuracy
                    )
                )
            }
        }
    }

    // ────────────────────────────────────────────────────────────────────────
    // ライフサイクル
    // ────────────────────────────────────────────────────────────────────────

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            ACTION_START -> {
                val name = intent.getStringExtra(EXTRA_ROUTE_NAME)
                    ?: defaultRouteName()
                startLogging(name)
            }
            ACTION_STOP -> stopLogging()
        }
        return START_NOT_STICKY
    }

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onDestroy() {
        super.onDestroy()
        fusedClient.removeLocationUpdates(locationCallback)
        scope.cancel()
        isRunning         = false
        currentRouteLogId = null
    }

    // ────────────────────────────────────────────────────────────────────────
    // 内部処理
    // ────────────────────────────────────────────────────────────────────────

    private fun startLogging(name: String) {
        createNotificationChannel()
        startForeground(NOTIF_ID, buildNotification(name))

        isRunning = true
        scope.launch {
            val id = routeLogRepository.startNewLog(name)
            currentLogId      = id
            currentRouteLogId = id
        }

        requestLocationUpdates()
    }

    private fun stopLogging() {
        val logId = currentLogId
        fusedClient.removeLocationUpdates(locationCallback)
        if (logId != null) {
            scope.launch {
                routeLogRepository.finishLog(logId)
                currentLogId      = null
                currentRouteLogId = null
                isRunning         = false
            }
        } else {
            isRunning         = false
            currentRouteLogId = null
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            stopForeground(STOP_FOREGROUND_REMOVE)
        } else {
            @Suppress("DEPRECATION")
            stopForeground(true)
        }
        stopSelf()
    }

    @SuppressLint("MissingPermission")
    private fun requestLocationUpdates() {
        val request = LocationRequest.Builder(
            Priority.PRIORITY_HIGH_ACCURACY,
            5_000L          // 5秒ごとに測位
        ).setMinUpdateDistanceMeters(3f).build()

        fusedClient.requestLocationUpdates(request, locationCallback, mainLooper)
    }

    private fun createNotificationChannel() {
        val channel = NotificationChannel(
            CHANNEL_ID,
            "経路ロガー",
            NotificationManager.IMPORTANCE_LOW
        ).apply {
            description = "移動経路を記録しています"
            setShowBadge(false)
        }
        getSystemService(NotificationManager::class.java)
            .createNotificationChannel(channel)
    }

    private fun buildNotification(routeName: String = "ルート"): Notification {
        val tapIntent = PendingIntent.getActivity(
            this, 0,
            Intent(this, MainActivity::class.java),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        return NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("経路記録中: $routeName")
            .setContentText("移動ルートを記録しています。タップしてアプリに戻る")
            .setSmallIcon(android.R.drawable.ic_menu_mylocation)
            .setOngoing(true)
            .setContentIntent(tapIntent)
            .build()
    }

    private fun defaultRouteName(): String {
        val fmt = java.time.format.DateTimeFormatter.ofPattern("MM/dd HH:mm")
        return "ルート ${java.time.LocalDateTime.now().format(fmt)}"
    }
}
