package com.example.offlinestore1

import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.Gravity
import android.view.View
import android.widget.EditText
import android.widget.HorizontalScrollView
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.setPadding
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import kotlin.concurrent.thread

class CategoryAppsActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: AppAdapter
    private lateinit var edtSearch: EditText
    private lateinit var prefs: PreferencesHelper
    private lateinit var chipsContainer: LinearLayout
    private lateinit var horizontalScrollView: HorizontalScrollView

    private var allApps: List<AppModel> = emptyList()
    private var visibleApps: MutableList<AppModel> = mutableListOf()
    private var selectedCategory: String = ""
    private var isGrid = false

    private val sessionToPackageMap = ConcurrentHashMap<Int, String>()

    private val installerCallback = object : PackageInstaller.SessionCallback() {
        override fun onCreated(sessionId: Int) {}
        override fun onBadgingChanged(sessionId: Int) {}
        override fun onActiveChanged(sessionId: Int, active: Boolean) {}
        
        override fun onProgressChanged(sessionId: Int, progress: Float) {
            val packageName = sessionToPackageMap[sessionId] ?: return
            val percent = (progress * 100).toInt().coerceIn(0, 100)
            updateAppState(
                packageName = packageName,
                isInstalled = false,
                installState = "installing",
                progress = percent,
                statusText = getString(R.string.state_installing, percent)
            )
        }

        override fun onFinished(sessionId: Int, success: Boolean) {
            sessionToPackageMap.remove(sessionId)
        }
    }

    private val installResultReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action != InstallReceiver.ACTION_INSTALL_RESULT) return

            val packageName = intent.getStringExtra(InstallReceiver.EXTRA_PACKAGE_NAME).orEmpty()
            val operation = intent.getStringExtra(InstallReceiver.EXTRA_OPERATION).orEmpty()
            val success = intent.getBooleanExtra("success", false)

            if (packageName.isBlank()) return

            if (operation == "install") {
                updateAppState(packageName, success, "idle", 0, "")
            } else if (operation == "uninstall") {
                updateAppState(packageName, !success, "idle", 0, "")
            }
        }
    }

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

        selectedCategory = getString(R.string.category_all)
        prefs = PreferencesHelper(this)
        isGrid = prefs.isGridMode()

        recyclerView = findViewById(R.id.recyclerViewApps)
        edtSearch = findViewById(R.id.edtSearch)
        chipsContainer = findViewById(R.id.chipsContainer)
        horizontalScrollView = chipsContainer.parent as HorizontalScrollView

        findViewById<ImageButton>(R.id.btnSettings).setOnClickListener {
            startActivity(Intent(this, SettingsActivity::class.java))
        }

        findViewById<ImageButton>(R.id.btnToggleView).setOnClickListener {
            isGrid = !isGrid
            prefs.saveViewMode(isGrid)
            applyLayoutManager()
            if (::adapter.isInitialized) {
                adapter.isGridMode = isGrid
                adapter.notifyDataSetChanged()
            }
        }

        edtSearch.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                applyFilters()
            }
            override fun afterTextChanged(s: Editable?) {}
        })

        applyLayoutManager()
        loadApps()
        
        packageManager.packageInstaller.registerSessionCallback(installerCallback)
    }

    override fun onDestroy() {
        super.onDestroy()
        try {
            packageManager.packageInstaller.unregisterSessionCallback(installerCallback)
        } catch (_: Exception) {}
    }

    override fun onResume() {
        super.onResume()
        if (prefs.hasPassword() && !LoginActivity.isAuthenticated) {
            val intent = Intent(this, LoginActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
            startActivity(intent)
            finish()
            return
        }
        refreshInstalledStates()
    }

    override fun onStart() {
        super.onStart()
        LoginActivity.runningActivities++

        val filter = IntentFilter(InstallReceiver.ACTION_INSTALL_RESULT)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(installResultReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
        } else {
            @Suppress("DEPRECATION")
            registerReceiver(installResultReceiver, filter)
        }
    }

    override fun onStop() {
        super.onStop()
        LoginActivity.runningActivities--
        if (LoginActivity.runningActivities <= 0) {
            LoginActivity.isAuthenticated = false
        }
        try {
            unregisterReceiver(installResultReceiver)
        } catch (_: Exception) {}
    }

    private fun applyLayoutManager() {
        recyclerView.layoutManager = if (isGrid) {
            GridLayoutManager(this, 2)
        } else {
            LinearLayoutManager(this)
        }
    }

    private fun loadApps() {
        allApps = scanAllApks("/system/app-data/")
        buildCategoryChips()
        applyFilters()

        adapter = AppAdapter(
            appList = visibleApps,
            isGridMode = isGrid,
            onPrimaryClick = { app ->
                if (app.isInstalled) {
                    val installedVersion = getInstalledVersionCode(app.packageName)
                    if (app.versionCode > installedVersion && installedVersion != -1) {
                        updateAppState(app.packageName, false, "copying", 0, getString(R.string.state_starting))
                        silentInstall(app)
                    } else {
                        openApp(app.packageName)
                    }
                } else {
                    updateAppState(app.packageName, false, "copying", 0, getString(R.string.state_starting))
                    silentInstall(app)
                }
            },
            onUninstallClick = { app -> confirmUninstall(app) }
        )
        recyclerView.adapter = adapter
        
        // גלילה לימין (התחלה ב-RTL)
        horizontalScrollView.post {
            horizontalScrollView.fullScroll(View.FOCUS_RIGHT)
        }
    }

    private fun scanAllApks(rootPath: String): List<AppModel> {
        val list = mutableListOf<AppModel>()
        val rootDir = File(rootPath)
        val pm = packageManager

        if (!rootDir.exists() || !rootDir.isDirectory) return emptyList()

        rootDir.listFiles()?.filter { it.isDirectory }?.forEach { categoryDir ->
            categoryDir.listFiles { _, name -> name.endsWith(".apk", ignoreCase = true) }?.forEach { file ->
                try {
                    val info = pm.getPackageArchiveInfo(file.absolutePath, 0)
                    info?.applicationInfo?.let { appInfo ->
                        val pkgName = info.packageName.trim()
                        val verCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                            info.longVersionCode.toInt()
                        } else {
                            @Suppress("DEPRECATION")
                            info.versionCode
                        }
                        
                        appInfo.sourceDir = file.absolutePath
                        appInfo.publicSourceDir = file.absolutePath
                        
                        list.add(AppModel(
                            name = appInfo.loadLabel(pm).toString().trim(),
                            icon = appInfo.loadIcon(pm),
                            packageName = pkgName,
                            apkFile = file,
                            isInstalled = isAppInstalled(pkgName),
                            category = categoryDir.name,
                            sizeText = AppModel.formatSize(file.length()),
                            versionCode = verCode
                        ))
                    }
                } catch (_: Exception) {}
            }
        }
        
        return list
            .groupBy { it.packageName.lowercase() }
            .map { entry -> entry.value.maxBy { it.versionCode } }
            .sortedBy { it.name.lowercase() }
    }

    private fun buildCategoryChips() {
        chipsContainer.removeAllViews()
        val allLabel = getString(R.string.category_all)
        val categories = mutableListOf(allLabel)
        categories.addAll(allApps.map { it.category }.distinct().sorted())

        categories.forEach { category ->
            val isSelected = category == selectedCategory
            val chip = TextView(this).apply {
                text = category
                textSize = 14f
                gravity = Gravity.CENTER
                
                background = getDrawable(if (isSelected) R.drawable.bg_chip_selected else R.drawable.bg_chip)
                setTextColor(if (isSelected) Color.parseColor("#4F46E5") else Color.parseColor("#475569"))
                
                val horizontalPx = 16.toPx()
                val verticalPx = 6.toPx()
                setPadding(horizontalPx, verticalPx, horizontalPx, verticalPx)
                
                setOnClickListener {
                    it.startClickAnimation()
                    selectedCategory = category
                    buildCategoryChips()
                    applyFilters()
                }
            }
            
            val params = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
            )
            params.marginStart = 6.toPx()
            params.topMargin = 2.toPx()
            params.bottomMargin = 2.toPx()
            chip.layoutParams = params
            
            chipsContainer.addView(chip)
        }
    }

    private fun Int.toPx(): Int = (this * resources.displayMetrics.density).toInt()

    private fun applyFilters() {
        val q = edtSearch.text.toString().trim().lowercase()
        val allLabel = getString(R.string.category_all)

        visibleApps.clear()
        
        val filtered = allApps.filter { app ->
            val categoryOk = selectedCategory == allLabel || app.category == selectedCategory
            val textOk = q.isEmpty() || app.name.lowercase().contains(q) || app.packageName.lowercase().contains(q)
            categoryOk && textOk
        }

        visibleApps.addAll(filtered)

        if (::adapter.isInitialized) {
            adapter.notifyDataSetChanged()
        }
    }

    private fun refreshInstalledStates() {
        allApps.forEach { app ->
            val installedNow = isAppInstalled(app.packageName)
            app.isInstalled = installedNow
            if (installedNow) {
                app.installState = "idle"
                app.progress = 0
                app.statusText = ""
            }
        }
        applyFilters()
    }

    private fun updateAppState(packageName: String, isInstalled: Boolean, installState: String, progress: Int, statusText: String) {
        runOnUiThread {
            allApps.forEach { app ->
                if (app.packageName == packageName) {
                    app.isInstalled = isInstalled
                    app.installState = installState
                    app.progress = progress
                    app.statusText = statusText
                }
            }
            applyFilters()
        }
    }

    private fun isAppInstalled(packageName: String): Boolean = getInstalledVersionCode(packageName) != -1

    private fun getInstalledVersionCode(packageName: String): Int {
        return try {
            val info = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
            } else {
                @Suppress("DEPRECATION")
                packageManager.getPackageInfo(packageName, 0)
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) info.longVersionCode.toInt() else @Suppress("DEPRECATION") info.versionCode
        } catch (_: Exception) { -1 }
    }

    private fun openApp(packageName: String) {
        val intent = packageManager.getLaunchIntentForPackage(packageName)
        if (intent != null) startActivity(intent) else Toast.makeText(this, getString(R.string.error_open_app), Toast.LENGTH_SHORT).show()
    }

    private fun silentInstall(app: AppModel) {
        thread {
            val apkFile = app.apkFile
            val installer = packageManager.packageInstaller
            val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)

            try {
                val sessionId = installer.createSession(params)
                val session = installer.openSession(sessionId)
                sessionToPackageMap[sessionId] = app.packageName

                apkFile.inputStream().use { input ->
                    session.openWrite("package_install", 0, apkFile.length()).use { output ->
                        val buffer = ByteArray(65536)
                        var total = 0L
                        var read: Int
                        while (input.read(buffer).also { read = it } != -1) {
                            output.write(buffer, 0, read)
                            total += read
                            val percent = ((total * 100) / apkFile.length()).toInt().coerceIn(0, 100)
                            updateAppState(app.packageName, false, "copying", percent, getString(R.string.state_copying, percent))
                        }
                        session.fsync(output)
                    }
                }
                updateAppState(app.packageName, false, "installing", 0, getString(R.string.state_installing, 0))
                val intent = Intent(this, InstallReceiver::class.java).apply {
                    putExtra(InstallReceiver.EXTRA_PACKAGE_NAME, app.packageName)
                    putExtra(InstallReceiver.EXTRA_OPERATION, "install")
                }
                val pendingIntent = PendingIntent.getBroadcast(this, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
                session.commit(pendingIntent.intentSender)
                session.close()
            } catch (e: Exception) {
                updateAppState(app.packageName, false, "idle", 0, "")
                runOnUiThread { Toast.makeText(this, getString(R.string.error_install, e.message), Toast.LENGTH_LONG).show() }
            }
        }
    }

    private fun confirmUninstall(app: AppModel) {
        AlertDialog.Builder(this)
            .setTitle(getString(R.string.dialog_uninstall_title))
            .setMessage(getString(R.string.dialog_uninstall_msg, app.name))
            .setPositiveButton(getString(R.string.btn_uninstall)) { _, _ -> uninstallPackage(app) }
            .setNegativeButton(getString(R.string.dialog_cancel), null)
            .show()
    }

    private fun uninstallPackage(app: AppModel) {
        try {
            val installer = packageManager.packageInstaller
            val intent = Intent(this, InstallReceiver::class.java).apply {
                putExtra(InstallReceiver.EXTRA_PACKAGE_NAME, app.packageName)
                putExtra(InstallReceiver.EXTRA_OPERATION, "uninstall")
            }
            val pendingIntent = PendingIntent.getBroadcast(this, app.packageName.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
            installer.uninstall(app.packageName, pendingIntent.intentSender)
            updateAppState(app.packageName, true, "installing", 0, getString(R.string.state_uninstalling))
        } catch (e: Exception) { Toast.makeText(this, getString(R.string.error_uninstall, e.message), Toast.LENGTH_LONG).show() }
    }
}
