package sh.sar.gridflow import android.content.Intent import android.os.Bundle import android.util.Log import android.view.MenuItem import android.view.View import android.widget.Toast import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.core.view.GravityCompat import androidx.lifecycle.lifecycleScope import com.google.android.material.navigation.NavigationView import kotlinx.coroutines.launch import sh.sar.gridflow.R import sh.sar.gridflow.data.BillLookupResponse import sh.sar.gridflow.databinding.ActivityPayWithoutAccountBinding import sh.sar.gridflow.network.ApiResult import sh.sar.gridflow.network.FenakaApiService import java.text.SimpleDateFormat import java.util.* class PayWithoutAccountActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { private var binding: ActivityPayWithoutAccountBinding? = null private lateinit var apiService: FenakaApiService private var currentBill: BillLookupResponse? = null private var drawerToggle: ActionBarDrawerToggle? = null companion object { private const val TAG = "PayWithoutAccountActivity" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Force system theme (follows device dark mode setting) AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) Log.d(TAG, "PayWithoutAccountActivity onCreate") // Check if toolbar should be hidden val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) if (hideToolbar) { // Use original layout for login context binding = ActivityPayWithoutAccountBinding.inflate(layoutInflater) setContentView(binding!!.root) binding!!.toolbar.visibility = View.GONE // Remove margin since toolbar is hidden val scrollView = findViewById(R.id.scroll_view) scrollView?.let { view -> val params = view.layoutParams as androidx.coordinatorlayout.widget.CoordinatorLayout.LayoutParams params.topMargin = 0 view.layoutParams = params } } else { // Use drawer layout for menu context setContentView(R.layout.activity_pay_without_account_drawer) // Don't use ViewBinding for drawer layout, access views manually setupDrawer() } apiService = FenakaApiService() setupClickListeners() } private fun setupDrawer() { val toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) supportActionBar?.apply { title = "Pay Without Account" } val drawerLayout = findViewById(R.id.drawer_layout) drawerToggle = ActionBarDrawerToggle( this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close ) drawerLayout.addDrawerListener(drawerToggle!!) drawerToggle?.syncState() val navView = findViewById(R.id.nav_view) navView.setNavigationItemSelectedListener(this) } // Helper methods to access views regardless of layout type private fun getBillDetailsCard(): com.google.android.material.card.MaterialCardView { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.billDetailsCard } else { findViewById(R.id.bill_details_card) } } private fun getInputFieldsLayout(): android.widget.LinearLayout { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.inputFieldsLayout } else { findViewById(R.id.input_fields_layout) } } private fun getBillNumberInput(): com.google.android.material.textfield.TextInputEditText { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.etBillNumber } else { findViewById(R.id.et_bill_number) } } private fun getSubscriptionNumberInput(): com.google.android.material.textfield.TextInputEditText { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.etSubscriptionNumber } else { findViewById(R.id.et_subscription_number) } } private fun getContinueButton(): com.google.android.material.button.MaterialButton { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.btnContinue } else { findViewById(R.id.btn_continue) } } // Additional helper methods for views that exist only in the original layout private fun getTvBillNumber(): android.widget.TextView? { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.tvBillNumber } else { findViewById(R.id.tv_bill_number) } } private fun getTvBillStatus(): android.widget.TextView? { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.tvBillStatus } else { findViewById(R.id.tv_bill_status) } } private fun getPayButton(): com.google.android.material.button.MaterialButton? { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) return if (hideToolbar) { binding!!.btnPay } else { findViewById(R.id.btn_pay) } } private fun setupClickListeners() { val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) if (hideToolbar) { // Use ViewBinding for original layout binding!!.btnContinue.setOnClickListener { handleContinue() } binding!!.btnPay.setOnClickListener { handlePayment() } } else { // Use findViewById for drawer layout val btnContinue = findViewById(R.id.btn_continue) val btnPay = findViewById(R.id.btn_pay) btnContinue.setOnClickListener { handleContinue() } btnPay.setOnClickListener { handlePayment() } } } private fun handleContinue() { // Check if we're showing the card - if so, hide it and show input fields if (getBillDetailsCard().visibility == View.VISIBLE) { Log.d(TAG, "Hiding bill details card and showing input fields") showInputFields() return } // Otherwise, perform bill search val billNumber = getBillNumberInput().text.toString().trim() val subscriptionNumber = getSubscriptionNumberInput().text.toString().trim() Log.d(TAG, "handleContinue called with bill: $billNumber, subscription: $subscriptionNumber") if (validateInput(billNumber, subscriptionNumber)) { Log.d(TAG, "Input validation passed, fetching bill details") fetchBillDetails(billNumber, subscriptionNumber) } else { Log.d(TAG, "Input validation failed") } } private fun showInputFields() { getInputFieldsLayout().visibility = View.VISIBLE getBillDetailsCard().visibility = View.GONE currentBill = null // Update button text to Continue when showing input fields getContinueButton().text = "Continue" } private fun fetchBillDetails(billNumber: String, subscriptionNumber: String) { setLoading(true) lifecycleScope.launch { try { when (val result = apiService.findBill(billNumber, subscriptionNumber)) { is ApiResult.Success -> { Log.d(TAG, "Bill fetch successful: ${result.data.billNumber}") currentBill = result.data setLoading(false) showBillDetails(result.data) } is ApiResult.Error -> { if (result.code == 404) { Log.d(TAG, "404 received, trying with swapped parameters") // Try again with swapped parameters when (val retryResult = apiService.findBill(subscriptionNumber, billNumber)) { is ApiResult.Success -> { Log.d(TAG, "Retry successful with swapped parameters: ${retryResult.data.billNumber}") currentBill = retryResult.data setLoading(false) showBillDetails(retryResult.data) } is ApiResult.Error -> { Log.d(TAG, "Retry also failed: ${retryResult.message} (code: ${retryResult.code})") setLoading(false) showError(retryResult.message) } } } else { Log.d(TAG, "Bill fetch failed: ${result.message} (code: ${result.code})") setLoading(false) showError(result.message) } } } } catch (e: Exception) { Log.e(TAG, "Exception in fetchBillDetails", e) setLoading(false) showError("Failed to fetch bill details: ${e.message}") } } } private fun handlePayment() { currentBill?.let { bill -> if (bill.status == "paid") { Toast.makeText(this, "This bill has already been paid", Toast.LENGTH_SHORT).show() } else { // Navigate to PaymentReviewActivity for single bill val intent = android.content.Intent(this, PaymentReviewActivity::class.java) intent.putExtra("SINGLE_BILL_ID", bill.id) intent.putExtra("SINGLE_BILL_AMOUNT", bill.billAmount) intent.putExtra("SINGLE_BILL_NUMBER", bill.billNumber) intent.putExtra("SINGLE_BILL_SUBSCRIPTION_ID", bill.subscription.id) startActivity(intent) } } } private fun showError(message: String) { Toast.makeText(this, message, Toast.LENGTH_LONG).show() // Show input fields and hide bill details showInputFields() // Don't clear input fields - user might have made a small mistake } private fun showBillDetails(bill: BillLookupResponse) { // Hide input fields and show bill details getInputFieldsLayout().visibility = View.GONE getBillDetailsCard().visibility = View.VISIBLE // Update button text to Search Another Bill when showing card getContinueButton().text = "Search Another Bill" // Set bill information (only set views that exist in both layouts) getTvBillNumber()?.text = bill.billNumber getTvBillStatus()?.text = bill.status.uppercase() // Set payment status and button val isPaid = bill.status == "paid" getPayButton()?.let { payButton -> payButton.isEnabled = !isPaid payButton.alpha = if (isPaid) 0.5f else 1.0f payButton.text = if (isPaid) "Already Paid" else "Pay MVR ${bill.billAmount}" } // Set status color based on payment status getTvBillStatus()?.let { statusView -> when (bill.status.lowercase()) { "paid" -> { statusView.setTextColor(getColor(android.R.color.holo_green_dark)) } "unpaid" -> { statusView.setTextColor(getColor(android.R.color.holo_red_dark)) } else -> { statusView.setTextColor(getColor(android.R.color.holo_orange_dark)) } } } // Note: Detailed bill information (customer name, address, etc.) // is only shown in the original layout from login screen val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) if (hideToolbar) { // Set detailed information only when using original layout binding!!.tvBillAmount.text = "MVR ${bill.billAmount}" binding!!.tvCustomerName.text = bill.customer.name binding!!.tvAccountNumber.text = bill.customer.accountNumber binding!!.tvPhoneNumber.text = bill.customer.phone val address = "${bill.subscriptionAddress.property.name}, ${bill.subscriptionAddress.property.street.name}" binding!!.tvAddress.text = address binding!!.tvSubscriptionNumber.text = bill.subscription.subscriptionNumber binding!!.tvServiceType.text = if (bill.subscription.serviceId == 1) "Electricity" else "Water" val dueDateFormatted = formatDate(bill.dueDate) val billDateFormatted = formatDate(bill.billDate) binding!!.tvDueDate.text = dueDateFormatted binding!!.tvBillDate.text = billDateFormatted // Show payment details if available bill.billPaymentDetails?.let { paymentDetails -> if (paymentDetails.paidAmount.toDoubleOrNull() ?: 0.0 > 0.0) { binding!!.tvPaidAmount.visibility = View.VISIBLE binding!!.tvPaidAmount.text = "Paid: MVR ${paymentDetails.paidAmount}" if (paymentDetails.pendingAmount.toDoubleOrNull() ?: 0.0 > 0.0) { binding!!.tvPendingAmount.visibility = View.VISIBLE binding!!.tvPendingAmount.text = "Pending: MVR ${paymentDetails.pendingAmount}" } } } } } private fun formatDate(dateString: String): String { return try { val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) val outputFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()) val date = inputFormat.parse(dateString) outputFormat.format(date ?: Date()) } catch (e: Exception) { Log.e(TAG, "Error formatting date: $dateString", e) dateString.substringBefore("T") } } private fun validateInput(billNumber: String, subscriptionNumber: String): Boolean { if (billNumber.isEmpty()) { getBillNumberInput().error = "Bill number is required" return false } if (subscriptionNumber.isEmpty()) { getSubscriptionNumberInput().error = "Subscription number is required" return false } // Basic validation - you can add more specific validation rules here if (billNumber.length < 3) { getBillNumberInput().error = "Bill number must be at least 3 characters" return false } if (subscriptionNumber.length < 3) { getSubscriptionNumberInput().error = "Subscription number must be at least 3 characters" return false } return true } private fun setLoading(isLoading: Boolean) { getContinueButton().isEnabled = !isLoading getContinueButton().text = if (isLoading) "Searching Bill..." else "Continue" getBillNumberInput().isEnabled = !isLoading getSubscriptionNumberInput().isEnabled = !isLoading if (isLoading) { getBillDetailsCard().visibility = View.GONE getInputFieldsLayout().visibility = View.VISIBLE } } override fun onSupportNavigateUp(): Boolean { onBackPressedDispatcher.onBackPressed() return true } override fun onNavigationItemSelected(item: android.view.MenuItem): Boolean { when (item.itemId) { R.id.nav_dashboard -> { val intent = Intent(this, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.putExtra("navigate_to", "dashboard") startActivity(intent) finish() } R.id.nav_bill_history -> { val intent = Intent(this, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.putExtra("navigate_to", "bill_history") startActivity(intent) finish() } R.id.nav_subscriptions -> { val intent = Intent(this, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.putExtra("navigate_to", "subscriptions") startActivity(intent) finish() } R.id.nav_band_rates -> { val intent = Intent(this, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.putExtra("navigate_to", "band_rates") startActivity(intent) finish() } R.id.nav_pay_any_bill -> { val intent = Intent(this, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.putExtra("navigate_to", "pay_any_bill") startActivity(intent) finish() } } val drawerLayout = findViewById(R.id.drawer_layout) drawerLayout?.closeDrawer(androidx.core.view.GravityCompat.START) return true } @Deprecated("Deprecated in Java") override fun onBackPressed() { // Check if toolbar is hidden (launched from login) val hideToolbar = intent.getBooleanExtra("hide_toolbar", false) if (hideToolbar) { // If launched from login, go back to login super.onBackPressed() } else { // If launched from main menu, check if drawer is open val drawerLayout = findViewById(R.id.drawer_layout) if (drawerLayout?.isDrawerOpen(androidx.core.view.GravityCompat.START) == true) { drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START) } else { super.onBackPressed() } } } }