package com.b2lmobitech.fieldcloudhrms

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.b2lmobitech.fieldcloudhrms.databinding.FragmentAttendanceBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.text.SimpleDateFormat
import java.util.*

class AttendanceFragment : Fragment() {

    private var _binding: FragmentAttendanceBinding? = null
    private val binding get() = _binding!!

    private lateinit var adapter: AttendanceAdapter

    // Tracks current viewed week
    private val calendar = Calendar.getInstance(Locale.getDefault())

    private var btnStatus = "IN"
    private var btnText = "Check In"
    private var checkInImageUrl: String? = null
    private var checkInSignatureUrl: String? = null
    private var currentLatitude: Double? = null
    private var currentLongitude: Double? = null
    private var todayShift: Shift? = null
    private var isLate = "no"
    private var lateMinutes = 0
    private var isEarly = "no"
    private var earlyMinutes = 0
    private var shift_id = ""


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentAttendanceBinding.inflate(inflater, container, false)

        setupRecyclerView()
        fetchCurrentWeekAttendance()
        setupCheckInButton()
        updateWeekRange()
        setupWeekNavigation()
        checkTodayAttendance()
        checkShiftAndToggleCheckIn()

        return binding.root
    }

    // ------------------------ WEEK UI GENERATION ------------------------

    private fun setupRecyclerView() {
        adapter = AttendanceAdapter(getWeekDates()) { selectedItem ->
            openAttendanceDetails(selectedItem)
        }
        binding.recyclerAttendance.layoutManager = LinearLayoutManager(requireContext())
        binding.recyclerAttendance.adapter = adapter
    }

    private fun setupWeekNavigation() {
        binding.imgBackWeek.setOnClickListener {
            calendar.add(Calendar.WEEK_OF_YEAR, -1)
            refreshWeekUI()
        }

        binding.imgForwardWeek.setOnClickListener {
            calendar.add(Calendar.WEEK_OF_YEAR, 1)
            refreshWeekUI()
        }
    }

    private fun openAttendanceDetails(item: AttendanceModel) {
        val intent = Intent(requireContext(), AttendanceDetailActivity::class.java)
        intent.putExtra("date", item.date)
        intent.putExtra("day", item.day)
        intent.putExtra("inTime", item.inTime)
        intent.putExtra("outTime", item.outTime)
        intent.putExtra("status", item.status)
        intent.putExtra("totalHours", item.totalHours)
        intent.putExtra("checkInImage",item.checkInImage)
        intent.putExtra("checkInSignature",item.checkInSignature)
        intent.putExtra("checkInLocation",item.checkInLocation)
        intent.putExtra("checkOutLocation",item.checkOutLocation)
        startActivity(intent)
    }


    private fun fetchCurrentWeekAttendance() {
        val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())

        val tempCal = calendar.clone() as Calendar
        tempCal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
        val weekStart = sdf.format(tempCal.time)

        tempCal.add(Calendar.DATE, 6)
        val weekEnd = sdf.format(tempCal.time)

        fetchWeekAttendance(weekStart, weekEnd)
    }

    private fun refreshWeekUI() {
//        adapter.updateData(getWeekDates())
        val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())

        val tempCal = calendar.clone() as Calendar
        tempCal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
        val weekStart = sdf.format(tempCal.time)

        tempCal.add(Calendar.DATE, 6)
        val weekEnd = sdf.format(tempCal.time)

        fetchWeekAttendance(weekStart, weekEnd)
        updateWeekRange()
    }

    private fun getWeekDates(): List<AttendanceModel> {
        val tempCal = calendar.clone() as Calendar
        tempCal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)

        val dateFormatter = SimpleDateFormat("dd", Locale.getDefault())
        val dayFormatter = SimpleDateFormat("EEE", Locale.getDefault())

        val weekList = ArrayList<AttendanceModel>()

        repeat(7) {
            val date = tempCal.time
            weekList.add(
                AttendanceModel(
                    dateFormatter.format(date),
                    dayFormatter.format(date),
                    "00:00",
                    "00:00",
                    "Absent",
                    "00:00",
                    "",
                    "",
                    "",
                    "",
                    "",
                    "00:00",
                    "00:00"
                )
            )
            tempCal.add(Calendar.DATE, 1)
        }

        return weekList
    }

    private fun updateWeekRange() {
        val tempCal = calendar.clone() as Calendar

        tempCal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
        val start = tempCal.time

        tempCal.add(Calendar.DATE, 6)
        val end = tempCal.time

        val dateFormat = SimpleDateFormat("dd-MMM-yyyy", Locale.getDefault())
        binding.txtRange.text = "${dateFormat.format(start)} - ${dateFormat.format(end)}"
    }


    // ------------------------ ATTENDANCE CHECK-IN ------------------------

    private fun setupCheckInButton() {
        binding.btnCheckIn.setOnClickListener {
            showLoading()
            validateAttendanceRules()

//            if (btnStatus == "IN") {
//                // OPEN THE CHECK IN DETAILS PAGE
//                val intent = Intent(requireContext(), CheckInDetailsActivity::class.java)
//                startActivityForResult(intent, 1001)
//            } else {
//                // Normal checkout process
//                performAttendanceAPICall()
//            }
        }
    }

    private fun performAttendanceAPICall() {
        val sharedPref = requireContext().getSharedPreferences("login_pref", Context.MODE_PRIVATE)
        val userId = sharedPref.getString("user_id", "")!!
        val orgId = sharedPref.getString("org_id", "")!!

        val currentDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
        val currentDateTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())

        val request = AttendanceRequest(
            userId = userId,
            organizationId = orgId,
            date = currentDate,
            dateTime = currentDateTime,
            status = btnStatus,
            source = "App",
            shift_id = shift_id,
            imageUrl = checkInImageUrl,
            signatureUrl = checkInSignatureUrl,
            latitude = currentLatitude?.toString(),
            longitude = currentLongitude?.toString(),
            isLate = isLate,
            lateMinutes = lateMinutes.toString(),
            isEarly = isEarly,
            earlyMinutes = earlyMinutes.toString()
        )

        sendAttendance(request)
    }


    private fun sendAttendance(request: AttendanceRequest) {
        lifecycleScope.launch {
            try {
                val response = withContext(Dispatchers.IO) {
                    RetrofitClient.instance.submitAttendance(request).execute()
                }

                hideLoading()
                val res = response.body()
                Log.d("ATTENDANCE_RESPONSE", "$res")

                if (res?.success == true) {
                    Toast.makeText(requireContext(), "Attendance Saved", Toast.LENGTH_SHORT).show()

                    when (btnStatus) {
                        "IN" -> {
                            btnStatus = "OUT"
                            binding.btnCheckIn.text = "Check Out"
                            binding.btnCheckIn.setBackgroundColor(
                                requireContext().getColor(R.color.red)
                            )
                        }
                        "OUT" -> {
                            btnStatus = "IN"
                            binding.btnCheckIn.text = "Check In"
                            binding.btnCheckIn.setBackgroundColor(
                                requireContext().getColor(R.color.green)
                            )
                        }
                    }

                    checkTodayAttendance()
                    fetchCurrentWeekAttendance()
                } else {
                    Toast.makeText(
                        requireContext(),
                        res?.message ?: "Failed to save",
                        Toast.LENGTH_SHORT
                    ).show()
                }

            } catch (e: Exception) {
                hideLoading()
                Toast.makeText(requireContext(), e.message, Toast.LENGTH_LONG).show()
            }
        }
    }

    private fun checkTodayAttendance() {
        val sharedPref = requireContext().getSharedPreferences("login_pref", Context.MODE_PRIVATE)
        val userId = sharedPref.getString("user_id", "")!!
        val orgId = sharedPref.getString("org_id", "")!!

        lifecycleScope.launch {
            try {
                val response = withContext(Dispatchers.IO) {
                    RetrofitClient.instance.checkTodayAttendance(userId, orgId).execute()
                }

                val res = response.body()
                if (res != null && res.success) {
                    when (res.status) {
                        "NOT_STARTED" -> {
                            btnStatus = "IN"
                            binding.btnCheckIn.text = "Check In"
                        }
                        "IN" -> {
                            btnStatus = "OUT"
                            binding.btnCheckIn.text = "Check Out"
                            binding.btnCheckIn.setBackgroundColor(requireContext().getColor(R.color.red))
                        }
                        "PRESENT" -> {
                            btnStatus = "IN"
                            binding.txtTotalHours.text = "Total Hours: ${res.totalHours}"
                            binding.btnCheckIn.text = "Check In"
                            binding.btnCheckIn.setBackgroundColor(requireContext().getColor(R.color.green))
                        }
                        "LEAVE" -> {
                            btnStatus = "LEAVE"
                        }
                    }
                    updateCheckInButtonVisibility()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun fetchWeekAttendance(weekStart: String, weekEnd: String) {
        val sharedPref = requireContext().getSharedPreferences("login_pref", Context.MODE_PRIVATE)
        val userId = sharedPref.getString("user_id", "")!!
        val orgId = sharedPref.getString("org_id", "")!!

        showLoading()
        lifecycleScope.launch {
            try {
                val response = withContext(Dispatchers.IO) {
                    RetrofitClient.instance.getWeekAttendance(userId, orgId, weekStart, weekEnd).execute()
                }

                val res = response.body()
                if (res != null && res.success) {
                    val weekData = withContext(Dispatchers.Default) {
                        res.data.map {
                            it.copy(
                                inTime = it.inTime.takeIf { t -> t.isNotEmpty() } ?: "--",
                                outTime = it.outTime.takeIf { t -> t.isNotEmpty() } ?: "--"
                            )
                        }
                    }

                    adapter.updateData(weekData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
                Toast.makeText(requireContext(), "Failed to fetch week attendance", Toast.LENGTH_SHORT).show()
            } finally {
                hideLoading()
            }
        }
    }


    // ------------------------ LIFECYCLE ------------------------

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == 1001 && resultCode == AppCompatActivity.RESULT_OK) {

            val imageUrl = data?.getStringExtra("image_url") ?: ""
            val signatureUrl = data?.getStringExtra("signature_url") ?: ""

            Log.d("CHECK_IN_DATA", "Image URL: $imageUrl, Signature URL: $signatureUrl")

            // Save temporarily for attendance API
            checkInImageUrl = imageUrl
            checkInSignatureUrl = signatureUrl

            // Now send final attendance request
            performAttendanceAPICall()
        }
    }

    private fun getCurrentLocation(onLocationReceived: (Double, Double) -> Unit) {

        val fusedClient = com.google.android.gms.location.LocationServices
            .getFusedLocationProviderClient(requireContext())

        if (androidx.core.content.ContextCompat.checkSelfPermission(
                requireContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION
            ) != android.content.pm.PackageManager.PERMISSION_GRANTED
        ) {
            requestPermissions(
                arrayOf(
                    android.Manifest.permission.ACCESS_FINE_LOCATION,
                    android.Manifest.permission.ACCESS_COARSE_LOCATION
                ),
                2001
            )
            hideLoading()
            return
        }

        val request = com.google.android.gms.location.LocationRequest.Builder(
            com.google.android.gms.location.Priority.PRIORITY_HIGH_ACCURACY,
            1000
        )
            .setWaitForAccurateLocation(true)
            .setMinUpdateIntervalMillis(1000)
            .setMaxUpdateDelayMillis(2000)
            .build()

        fusedClient.requestLocationUpdates(request, object :
            com.google.android.gms.location.LocationCallback() {

            override fun onLocationResult(result: com.google.android.gms.location.LocationResult) {
                val freshLoc = result.lastLocation

                if (freshLoc != null) {

                    // RETURN FRESH LOCATION
                    onLocationReceived(freshLoc.latitude, freshLoc.longitude)

                    // STOP UPDATES
                    fusedClient.removeLocationUpdates(this)
                }
            }
        }, null)
    }

    private fun validateAttendanceRules() {

        val sharedPref = requireContext().getSharedPreferences("login_pref", Context.MODE_PRIVATE)
        val userId = sharedPref.getString("user_id", "")!!
        val orgId = sharedPref.getString("org_id", "")!!

        getCurrentLocation { lat, lon ->

            currentLatitude = lat
            currentLongitude = lon

            lifecycleScope.launch {
                try {

                    val response = withContext(Dispatchers.IO) {
                        RetrofitClient.instance
                            .getAttendanceConfig(userId, orgId)
                            .execute()
                    }

                    val res = response.body()
                    if (res?.success != true) {
                        hideLoading()
                        Toast.makeText(requireContext(), "Config error", Toast.LENGTH_SHORT).show()
                        return@launch
                    }

                    //  Heavy calculation moved off main thread
                    val insideGeofence = withContext(Dispatchers.Default) {
                        if (!res.geofence.equals("YES", true)) return@withContext true

                        res.locations.any { loc ->
                            val distance = calculateDistance(
                                lat, lon,
                                loc.latitude.toDouble(),
                                loc.longitude.toDouble()
                            )
                            distance <= loc.geofence_distance.toDouble()
                        }
                    }

                    if (!insideGeofence) {
                        hideLoading()
                        showOutOfGeofenceDialog()
                        return@launch
                    }

                    handleCheckInImageRule(res)

                } catch (e: Exception) {
                    hideLoading()
                    Toast.makeText(requireContext(), e.message, Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    private fun checkShiftAndToggleCheckIn() {
        val pref = requireContext().getSharedPreferences("login_pref", Context.MODE_PRIVATE)
        val userId = pref.getString("user_id", "")!!
        val orgId = pref.getString("org_id", "")!!

        lifecycleScope.launch {
            try {
                val response = withContext(Dispatchers.IO) {
                    RetrofitClient.instance.getTodayShift(userId, orgId).execute()
                }

                val res = response.body()
                if (res?.success == true && res.shift != null) {
                    todayShift = res.shift
                    applyShiftTimeRule(res.shift)
                } else {
                    todayShift = null
                    updateCheckInButtonVisibility()
                }
            } catch (e: Exception) {
                e.printStackTrace()
                todayShift = null
                updateCheckInButtonVisibility()
            }
        }
    }

    private fun applyShiftTimeRule(shift: Shift) {

        val timeFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
        val nowCal = Calendar.getInstance()

        // Shift start time
        val fromCal = Calendar.getInstance()
        val fromTime = timeFormat.parse(shift.from_time) ?: run {
            binding.btnCheckIn.visibility = View.GONE
            return
        }

        fromCal.set(Calendar.HOUR_OF_DAY, fromTime.hours)
        fromCal.set(Calendar.MINUTE, fromTime.minutes)
        fromCal.set(Calendar.SECOND, 0)

        // SAFE conversion (null → 0)
        val beforeMargin = shift.before_margin?.toIntOrNull() ?: 0
        val permissionMinutes = shift.permissionMinutes?.toIntOrNull() ?: 0

        val endCheckInCal = fromCal.clone() as Calendar
        endCheckInCal.add(Calendar.MINUTE, beforeMargin)
        endCheckInCal.add(Calendar.MINUTE, permissionMinutes)

//        val isAllowed =
//            nowCal.after(fromCal) && nowCal.before(endCheckInCal)

        Log.d(
            "SHIFT_CHECK",
            "Now=${nowCal.time}, From=${fromCal.time}, AllowedTill=${endCheckInCal.time}"
        )

//        binding.btnCheckIn.visibility =
//            if (isAllowed) View.VISIBLE else View.GONE
//        binding.btnCheckIn.visibility = when (btnStatus) {
//            "IN" -> View.VISIBLE
//            "OUT" -> View.VISIBLE
//            else -> View.GONE
//        }
    }


//    private fun handleCheckInImageRule(config: UserAttendanceConfigResponse) {
//
//        if (btnStatus == "IN") {
//
//            if (config.checkin_image.equals("YES", true)) {
//                // Open Check-in details page
//                val intent = Intent(requireContext(), CheckInDetailsActivity::class.java)
//                startActivityForResult(intent, 1001)
//
//            } else {
//                // Direct check-in without image
//                checkInImageUrl = ""
//                checkInSignatureUrl = ""
//                performAttendanceAPICall()
//            }
//
//        } else {
//            checkEarlyCheckoutAndConfirm()
//        }
//    }
    private fun handleCheckInImageRule(config: UserAttendanceConfigResponse) {

        if (btnStatus != "IN") {
            checkEarlyCheckoutAndConfirm()
            return
        }

        val shift = todayShift ?: run {
            proceedCheckIn(config)
            return
        }

        val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
        timeFormat.isLenient = false

        val nowCal = Calendar.getInstance()

        val fromTime = timeFormat.parse(shift.from_time) ?: run {
            hideLoading()
            Toast.makeText(requireContext(), "Invalid shift time", Toast.LENGTH_SHORT).show()
            return
        }

        val shiftStartCal = Calendar.getInstance().apply {
            time = fromTime
            set(Calendar.YEAR, nowCal.get(Calendar.YEAR))
            set(Calendar.MONTH, nowCal.get(Calendar.MONTH))
            set(Calendar.DAY_OF_MONTH, nowCal.get(Calendar.DAY_OF_MONTH))
            set(Calendar.SECOND, 0)
        }

        val allowedCheckinCal = shiftStartCal.clone() as Calendar
        allowedCheckinCal.add(Calendar.MINUTE, shift.before_margin.toInt())

        shift_id = shift.shift_id

        Log.d(
            "CHECKIN_DEBUG",
            "Now=${nowCal.time}, ShiftStart=${shiftStartCal.time}"
        )

        when {
            nowCal.before(shiftStartCal) -> {
                earlyMinutes =
                    ((shiftStartCal.timeInMillis - nowCal.timeInMillis) / 60000).toInt()
                isEarly = "yes"

                showEarlyCheckInConfirmDialog(
                    SimpleDateFormat("hh:mm a", Locale.getDefault()).format(shiftStartCal.time),
                    config
                )
            }

            nowCal.after(allowedCheckinCal) -> {
                lateMinutes =
                    ((nowCal.timeInMillis - shiftStartCal.timeInMillis) / 60000).toInt()
                isLate = "yes"

                showLateCheckInDialog(lateMinutes, config)
            }

            else -> {
                proceedCheckIn(config)
            }
        }
    }

    private fun checkEarlyCheckoutAndConfirm() {

        val shift = todayShift ?: run {
            // No shift info → allow checkout
            performAttendanceAPICall()
            return
        }

        val timeFormat = SimpleDateFormat("HH:mm", Locale.getDefault())

        val nowCal = Calendar.getInstance()

        // Shift end time (today)
        val toTime = timeFormat.parse(shift.to_time)!!
        val shiftEndCal = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, toTime.hours)
            set(Calendar.MINUTE, toTime.minutes)
            set(Calendar.SECOND, 0)
        }

        // shift.to_time - after_margin
        val allowedCheckoutCal = shiftEndCal.clone() as Calendar
        allowedCheckoutCal.add(Calendar.MINUTE, -shift.after_margin.toInt())

        // If checking out early
        if (nowCal.before(allowedCheckoutCal)) {

            val displayFormat = SimpleDateFormat("hh:mm a", Locale.getDefault())
            val allowedTimeText = displayFormat.format(allowedCheckoutCal.time)

            showEarlyCheckoutDialog(allowedTimeText)

        } else {
            // Normal checkout allowed
            performAttendanceAPICall()
        }
    }

    private fun showEarlyCheckoutDialog(allowedTime: String) {
        hideLoading()
        androidx.appcompat.app.AlertDialog.Builder(requireContext())
            .setTitle("Early Check-out")
            .setMessage(
                "Your shift ends at $allowedTime.\n\nAre you sure you want to check out now?"
            )
            .setPositiveButton("Yes") { _, _ ->
                performAttendanceAPICall()
            }
            .setNegativeButton("No") { dialog, _ ->
                dialog.dismiss()
            }
            .show()
    }

    private fun calculateDistance(
        lat1: Double, lon1: Double,
        lat2: Double, lon2: Double
    ): Double {
        val R = 6371000.0 // Earth radius in meters
        val dLat = Math.toRadians(lat2 - lat1)
        val dLon = Math.toRadians(lon2 - lon1)

        val a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(lat1)) *
                Math.cos(Math.toRadians(lat2)) *
                Math.sin(dLon / 2) *
                Math.sin(dLon / 2)

        val c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
        return R * c
    }

    private fun showOutOfGeofenceDialog() {
        hideLoading()
        androidx.appcompat.app.AlertDialog.Builder(requireContext())
            .setTitle("Out of Geofence")
            .setMessage("You are outside the allowed attendance area.")
            .setPositiveButton("OK", null)
            .show()
    }

    private fun proceedCheckIn(config: UserAttendanceConfigResponse) {
        hideLoading()
        if (config.checkin_image.equals("YES", true)) {
            val intent = Intent(requireContext(), CheckInDetailsActivity::class.java)
            startActivityForResult(intent, 1001)
        } else {
            checkInImageUrl = ""
            checkInSignatureUrl = ""
            performAttendanceAPICall()
        }
    }

    private fun showEarlyCheckInConfirmDialog(
        shiftStartTime: String,
        config: UserAttendanceConfigResponse
    ) {
        hideLoading()
        androidx.appcompat.app.AlertDialog.Builder(requireContext())
            .setTitle("Early Check-in")
            .setMessage(
                "You are early to check in.\n\n" +
                        "Your shift starts at $shiftStartTime.\n\n" +
                        "Are you sure you want to check in?"
            )
            .setPositiveButton("Yes") { _, _ ->
                proceedCheckIn(config)
            }
            .setNegativeButton("No") { dialog, _ ->
                dialog.dismiss()
            }
            .show()
    }

    private fun showLateCheckInDialog(lateMinutes: Int, config: UserAttendanceConfigResponse) {
        hideLoading()
        androidx.appcompat.app.AlertDialog.Builder(requireContext())
            .setTitle("Late Check-in")
            .setMessage("You are late to check in by $lateMinutes minutes.")
            .setPositiveButton("OK") { _, _ ->
                // Still allow check-in
                proceedCheckIn(config)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    private fun updateCheckInButtonVisibility() {
        when (btnStatus) {
            "IN", "OUT" -> binding.btnCheckIn.visibility = View.VISIBLE
            else -> binding.btnCheckIn.visibility = View.GONE
        }
    }

    private fun showLoading() {
        binding.progressCheckIn.visibility = View.VISIBLE
        binding.btnCheckIn.isEnabled = false
    }

    private fun hideLoading() {
        binding.progressCheckIn.visibility = View.GONE
        binding.btnCheckIn.isEnabled = true
    }


}
