package com.example.maposition

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.location.Location
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.telephony.SmsManager
import android.view.View
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.google.android.gms.tasks.CancellationTokenSource
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.CircularProgressIndicator
import java.util.concurrent.TimeUnit

class MainActivity : AppCompatActivity() {

    companion object {
        private const val ACTION_SMS_SENT = "com.example.maposition.SMS_SENT"
        private const val EXTRA_RECIPIENT = "recipient"
        private const val REQUEST_PERMISSIONS = 1
        private const val LOCATION_TIMEOUT_MS = 10_000L
        private const val SEND_STAGGER_MS = 500L
        private const val REPORT_TIMEOUT_MS = 20_000L
    }

    private val permissions = arrayOf(
        Manifest.permission.SEND_SMS,
        Manifest.permission.ACCESS_FINE_LOCATION
    )

    private val handler = Handler(Looper.getMainLooper())

    private lateinit var sendButton: MaterialButton
    private lateinit var statusText: TextView
    private lateinit var progress: CircularProgressIndicator
    private lateinit var recipientsText: TextView

    // État d'un envoi en cours
    private var busy = false
    private var expectedReports = 0
    private var receivedReports = 0
    private var successCount = 0
    private val failedNumbers = mutableListOf<String>()
    private var reportTimeout: Runnable? = null

    private val smsSentReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (!busy) return
            val num = intent.getStringExtra(EXTRA_RECIPIENT) ?: "?"
            receivedReports++
            if (resultCode == Activity.RESULT_OK) successCount++ else failedNumbers.add(num)
            if (receivedReports >= expectedReports) {
                finishSending()
            } else {
                setStatus(getString(R.string.status_sending_progress, receivedReports, expectedReports))
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sendButton = findViewById(R.id.sendButton)
        statusText = findViewById(R.id.statusText)
        progress = findViewById(R.id.progress)
        recipientsText = findViewById(R.id.recipientsText)

        ContextCompat.registerReceiver(
            this, smsSentReceiver, IntentFilter(ACTION_SMS_SENT),
            ContextCompat.RECEIVER_NOT_EXPORTED
        )

        sendButton.setOnClickListener { startSendFlow() }
        findViewById<ImageButton>(R.id.settingsButton).setOnClickListener { openSettings() }
        findViewById<MaterialCardView>(R.id.recipientsCard).setOnClickListener { openSettings() }
    }

    override fun onResume() {
        super.onResume()
        refreshRecipientsCard()
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(smsSentReceiver)
        handler.removeCallbacksAndMessages(null)
    }

    private fun openSettings() {
        startActivity(Intent(this, SettingsActivity::class.java))
    }

    private fun getSavedSettings(): Pair<String, List<String>> {
        val prefs = getSharedPreferences("MaPositionPrefs", MODE_PRIVATE)
        val name = prefs.getString("name", "") ?: ""
        val phones = prefs.getString("phones", "") ?: ""
        val phoneList = phones.split(";").map { it.trim() }.filter { it.isNotEmpty() }
        return Pair(name, phoneList)
    }

    private fun refreshRecipientsCard() {
        val (name, phones) = getSavedSettings()
        recipientsText.text = if (phones.isEmpty()) {
            getString(R.string.recipients_none)
        } else {
            val who = if (name.isBlank()) "" else "$name → "
            who + phones.joinToString(", ")
        }
    }

    private fun startSendFlow() {
        if (busy) return
        val (_, phones) = getSavedSettings()
        if (phones.isEmpty()) {
            setStatus(getString(R.string.status_no_recipients))
            openSettings()
            return
        }
        if (!hasPermissions()) {
            ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS)
        } else {
            locateAndSend()
        }
    }

    private fun hasPermissions(): Boolean = permissions.all { perm ->
        ContextCompat.checkSelfPermission(this, perm) == PackageManager.PERMISSION_GRANTED
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, perms: Array<out String>, results: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, perms, results)
        if (requestCode != REQUEST_PERMISSIONS) return
        if (results.isNotEmpty() && results.all { it == PackageManager.PERMISSION_GRANTED }) {
            locateAndSend()
        } else {
            setStatus(getString(R.string.status_need_permissions))
        }
    }

    // --- Localisation : position fraîche, sinon repli sur la dernière connue ---

    @SuppressLint("MissingPermission")
    private fun locateAndSend() {
        busy = true
        resetReportState()
        sendButton.isEnabled = false
        progress.visibility = View.VISIBLE
        setStatus(getString(R.string.status_locating))

        val fused = LocationServices.getFusedLocationProviderClient(this)
        val cts = CancellationTokenSource()
        var settled = false

        val timeout = Runnable {
            if (!settled) {
                settled = true
                cts.cancel()
                fallbackToLastLocation(fused)
            }
        }
        handler.postDelayed(timeout, LOCATION_TIMEOUT_MS)

        fused.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, cts.token)
            .addOnSuccessListener { loc ->
                if (settled) return@addOnSuccessListener
                settled = true
                handler.removeCallbacks(timeout)
                if (loc != null) sendSmsWithLocation(loc, stale = false)
                else fallbackToLastLocation(fused)
            }
            .addOnFailureListener {
                if (settled) return@addOnFailureListener
                settled = true
                handler.removeCallbacks(timeout)
                fallbackToLastLocation(fused)
            }
    }

    @SuppressLint("MissingPermission")
    private fun fallbackToLastLocation(fused: FusedLocationProviderClient) {
        setStatus(getString(R.string.status_fallback))
        fused.lastLocation
            .addOnSuccessListener { loc ->
                if (loc != null) sendSmsWithLocation(loc, stale = true)
                else abort(getString(R.string.status_no_location))
            }
            .addOnFailureListener { abort(getString(R.string.status_no_location)) }
    }

    // --- Envoi des SMS avec accusé d'envoi et espacement ---

    private fun smsManager(): SmsManager =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            getSystemService(SmsManager::class.java)
        } else {
            @Suppress("DEPRECATION")
            SmsManager.getDefault()
        }

    private fun sendSmsWithLocation(location: Location, stale: Boolean) {
        val (name, phones) = getSavedSettings()

        val link = "https://maps.google.com/?q=${location.latitude},${location.longitude}"
        val ageMin = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - location.time)
        val staleSuffix = if (stale && ageMin >= 2) getString(R.string.msg_stale_suffix, ageMin) else ""
        val who = name.ifBlank { getString(R.string.msg_default_name) }.take(40)
        val message = getString(R.string.msg_body, who, link) + staleSuffix

        expectedReports = phones.size
        setStatus(getString(R.string.status_sending_progress, 0, expectedReports))

        val piFlags = PendingIntent.FLAG_ONE_SHOT or
                (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
        val requestBase = (SystemClock.elapsedRealtime() and 0xFFFFF).toInt()

        phones.forEachIndexed { i, num ->
            handler.postDelayed({
                try {
                    val sentIntent = Intent(ACTION_SMS_SENT)
                        .setPackage(packageName)
                        .putExtra(EXTRA_RECIPIENT, num)
                    val pi = PendingIntent.getBroadcast(this, requestBase + i, sentIntent, piFlags)
                    smsManager().sendTextMessage(num, null, message, pi, null)
                } catch (e: Exception) {
                    receivedReports++
                    failedNumbers.add(num)
                    if (receivedReports >= expectedReports) finishSending()
                }
            }, i * SEND_STAGGER_MS)
        }

        // Garde-fou : si l'opérateur ne confirme pas tous les envois, on conclut quand même
        reportTimeout = Runnable { finishSending() }.also {
            handler.postDelayed(it, phones.size * SEND_STAGGER_MS + REPORT_TIMEOUT_MS)
        }
    }

    private fun finishSending() {
        reportTimeout?.let { handler.removeCallbacks(it) }
        reportTimeout = null
        val unconfirmed = expectedReports - receivedReports
        val status = when {
            failedNumbers.isNotEmpty() ->
                getString(
                    R.string.status_sent_partial,
                    successCount, expectedReports, failedNumbers.joinToString(", ")
                )
            unconfirmed > 0 ->
                getString(R.string.status_sent_unconfirmed, successCount, unconfirmed)
            else ->
                getString(R.string.status_sent_ok, successCount)
        }
        resetUi()
        setStatus(status)
    }

    private fun abort(message: String) {
        resetUi()
        setStatus(message)
    }

    private fun resetUi() {
        busy = false
        progress.visibility = View.GONE
        sendButton.isEnabled = true
    }

    private fun resetReportState() {
        expectedReports = 0
        receivedReports = 0
        successCount = 0
        failedNumbers.clear()
    }

    private fun setStatus(text: String) {
        statusText.text = text
    }
}
