package com.narutohuo.xindazhou.core.util

import android.content.Context

/**
 * 工具类接口
 * 通用工具方法、时间处理、字符串处理、加密解密、设备信息、单位转换等
 * 
 * 所有SDK模块通过此接口使用工具类
 * 实现类由app模块提供
 */
interface IUtil {
    
    // ==================== 时间处理 ====================
    
    /**
     * 格式化时间戳为字符串
     * @param timestamp 时间戳（毫秒）
     * @param pattern 格式模式（如：yyyy-MM-dd HH:mm:ss）
     * @return 格式化后的时间字符串
     */
    fun formatTime(timestamp: Long, pattern: String): String
    
    /**
     * 解析时间字符串为时间戳
     * @param timeString 时间字符串
     * @param pattern 格式模式（如：yyyy-MM-dd HH:mm:ss）
     * @return 时间戳（毫秒），解析失败返回 null
     */
    fun parseTime(timeString: String, pattern: String): Long?
    
    /**
     * 获取当前时间戳（毫秒）
     */
    fun getCurrentTimeMillis(): Long
    
    /**
     * 格式化当前时间为字符串
     * @param pattern 格式模式
     * @return 格式化后的时间字符串
     */
    fun formatCurrentTime(pattern: String): String
    
    /**
     * 格式化日期（只包含日期部分）
     * @param timestamp 时间戳（毫秒）
     * @param pattern 格式模式（如：yyyy-MM-dd）
     * @return 格式化后的日期字符串
     */
    fun formatDate(timestamp: Long, pattern: String): String
    
    /**
     * 获取相对时间描述（如：刚刚、5分钟前、1小时前、昨天、3天前）
     * @param timestamp 时间戳（毫秒）
     * @return 相对时间描述
     */
    fun getRelativeTime(timestamp: Long): String
    
    // ==================== 字符串处理 ====================
    
    /**
     * 加密字符串
     * @param data 原始字符串
     * @return 加密后的字符串
     */
    fun encryptString(data: String): String
    
    /**
     * 解密字符串
     * @param data 加密后的字符串
     * @return 解密后的原始字符串
     */
    fun decryptString(data: String): String
    
    /**
     * MD5 加密
     * @param data 原始字符串
     * @return MD5 加密后的字符串（32位小写）
     */
    fun md5(data: String): String
    
    /**
     * Base64 编码
     * @param data 原始字符串
     * @return Base64 编码后的字符串
     */
    fun base64Encode(data: String): String
    
    /**
     * Base64 解码
     * @param data Base64 编码后的字符串
     * @return 解码后的原始字符串
     */
    fun base64Decode(data: String): String?
    
    /**
     * URL 编码
     * @param data 原始字符串
     * @return URL 编码后的字符串
     */
    fun urlEncode(data: String): String
    
    /**
     * URL 解码
     * @param data URL 编码后的字符串
     * @return 解码后的原始字符串
     */
    fun urlDecode(data: String): String?
    
    /**
     * 判断字符串是否为空（null、空字符串、纯空格）
     * @param str 待判断的字符串
     * @return true 表示为空
     */
    fun isEmpty(str: String?): Boolean
    
    /**
     * 判断字符串是否不为空
     * @param str 待判断的字符串
     * @return true 表示不为空
     */
    fun isNotEmpty(str: String?): Boolean
    
    /**
     * 去除字符串首尾空格
     * @param str 原始字符串
     * @return 去除空格后的字符串
     */
    fun trim(str: String?): String?
    
    /**
     * 字符串截取（安全截取，防止越界）
     * @param str 原始字符串
     * @param start 起始位置
     * @param end 结束位置
     * @return 截取后的字符串
     */
    fun substring(str: String, start: Int, end: Int): String?
    
    // ==================== 数据转换 ====================
    
    /**
     * 对象转 JSON 字符串
     * @param obj 待转换的对象
     * @return JSON 字符串
     */
    fun <T> toJson(obj: T): String
    
    /**
     * JSON 字符串转对象
     * @param json JSON 字符串
     * @param clazz 目标类型
     * @return 转换后的对象，转换失败返回 null
     */
    fun <T> fromJson(json: String, clazz: Class<T>): T?
    
    /**
     * JSON 字符串转对象（使用 TypeToken）
     * @param json JSON 字符串
     * @param typeToken 类型标记（如：object : TypeToken<List<String>>() {}）
     * @return 转换后的对象，转换失败返回 null
     */
    fun <T> fromJson(json: String, typeToken: Any): T?
    
    /**
     * 数字转字符串（安全转换，null 返回空字符串）
     * @param number 数字
     * @return 字符串
     */
    fun numberToString(number: Number?): String
    
    /**
     * 字符串转整数（安全转换，失败返回默认值）
     * @param str 字符串
     * @param defaultValue 默认值
     * @return 整数
     */
    fun stringToInt(str: String?, defaultValue: Int = 0): Int
    
    /**
     * 字符串转长整数（安全转换，失败返回默认值）
     * @param str 字符串
     * @param defaultValue 默认值
     * @return 长整数
     */
    fun stringToLong(str: String?, defaultValue: Long = 0L): Long
    
    /**
     * 字符串转浮点数（安全转换，失败返回默认值）
     * @param str 字符串
     * @param defaultValue 默认值
     * @return 浮点数
     */
    fun stringToFloat(str: String?, defaultValue: Float = 0f): Float
    
    /**
     * 字符串转双精度浮点数（安全转换，失败返回默认值）
     * @param str 字符串
     * @param defaultValue 默认值
     * @return 双精度浮点数
     */
    fun stringToDouble(str: String?, defaultValue: Double = 0.0): Double
    
    /**
     * 字符串转布尔值（安全转换，失败返回默认值）
     * @param str 字符串
     * @param defaultValue 默认值
     * @return 布尔值
     */
    fun stringToBoolean(str: String?, defaultValue: Boolean = false): Boolean
    
    // ==================== 设备信息 ====================
    
    /**
     * 获取屏幕宽度（像素）
     * @param context 上下文
     * @return 屏幕宽度（px）
     */
    fun getScreenWidth(context: Context): Int
    
    /**
     * 获取屏幕高度（像素）
     * @param context 上下文
     * @return 屏幕高度（px）
     */
    fun getScreenHeight(context: Context): Int
    
    /**
     * 获取状态栏高度（像素）
     * @param context 上下文
     * @return 状态栏高度（px）
     */
    fun getStatusBarHeight(context: Context): Int
    
    /**
     * 获取导航栏高度（像素）
     * @param context 上下文
     * @return 导航栏高度（px）
     */
    fun getNavigationBarHeight(context: Context): Int
    
    /**
     * 获取设备 ID（唯一标识）
     * @param context 上下文
     * @return 设备 ID
     */
    fun getDeviceId(context: Context): String
    
    /**
     * 获取应用版本号
     * @param context 上下文
     * @return 版本号（如：1.0.0）
     */
    fun getAppVersionName(context: Context): String
    
    /**
     * 获取应用版本码
     * @param context 上下文
     * @return 版本码（如：1）
     */
    fun getAppVersionCode(context: Context): Int
    
    /**
     * 获取应用包名
     * @param context 上下文
     * @return 包名
     */
    fun getPackageName(context: Context): String
    
    // ==================== 单位转换 ====================
    
    /**
     * dp 转 px
     * @param context 上下文
     * @param dp dp 值
     * @return px 值
     */
    fun dpToPx(context: Context, dp: Float): Int
    
    /**
     * px 转 dp
     * @param context 上下文
     * @param px px 值
     * @return dp 值
     */
    fun pxToDp(context: Context, px: Float): Float
    
    /**
     * sp 转 px
     * @param context 上下文
     * @param sp sp 值
     * @return px 值
     */
    fun spToPx(context: Context, sp: Float): Int
    
    /**
     * px 转 sp
     * @param context 上下文
     * @param px px 值
     * @return sp 值
     */
    fun pxToSp(context: Context, px: Float): Float
    
    // ==================== 文件操作 ====================
    
    /**
     * 读取文件内容（文本）
     * @param filePath 文件路径
     * @param charset 字符编码（默认 UTF-8）
     * @return 文件内容，读取失败返回 null
     */
    fun readFile(filePath: String, charset: String = "UTF-8"): String?
    
    /**
     * 写入文件内容（文本）
     * @param filePath 文件路径
     * @param content 文件内容
     * @param charset 字符编码（默认 UTF-8）
     * @param append 是否追加（true 追加，false 覆盖）
     * @return 是否写入成功
     */
    fun writeFile(filePath: String, content: String, charset: String = "UTF-8", append: Boolean = false): Boolean
    
    /**
     * 读取文件内容（字节）
     * @param filePath 文件路径
     * @return 文件内容（字节数组），读取失败返回 null
     */
    fun readFileBytes(filePath: String): ByteArray?
    
    /**
     * 写入文件内容（字节）
     * @param filePath 文件路径
     * @param bytes 文件内容（字节数组）
     * @param append 是否追加（true 追加，false 覆盖）
     * @return 是否写入成功
     */
    fun writeFileBytes(filePath: String, bytes: ByteArray, append: Boolean = false): Boolean
    
    /**
     * 删除文件
     * @param filePath 文件路径
     * @return 是否删除成功
     */
    fun deleteFile(filePath: String): Boolean
    
    /**
     * 判断文件是否存在
     * @param filePath 文件路径
     * @return 是否存在
     */
    fun fileExists(filePath: String): Boolean
    
    /**
     * 获取文件大小（字节）
     * @param filePath 文件路径
     * @return 文件大小，文件不存在返回 -1
     */
    fun getFileSize(filePath: String): Long
    
    /**
     * 复制文件
     * @param srcPath 源文件路径
     * @param destPath 目标文件路径
     * @return 是否复制成功
     */
    fun copyFile(srcPath: String, destPath: String): Boolean
    
    // ==================== 其他工具方法 ====================
    
    /**
     * 获取随机字符串
     * @param length 字符串长度
     * @param includeNumbers 是否包含数字
     * @param includeLetters 是否包含字母
     * @return 随机字符串
     */
    fun getRandomString(length: Int, includeNumbers: Boolean = true, includeLetters: Boolean = true): String
    
    /**
     * 获取随机整数
     * @param min 最小值（包含）
     * @param max 最大值（包含）
     * @return 随机整数
     */
    fun getRandomInt(min: Int, max: Int): Int
    
    /**
     * 格式化文件大小（如：1.5 MB、500 KB）
     * @param size 文件大小（字节）
     * @return 格式化后的字符串
     */
    fun formatFileSize(size: Long): String
    
    /**
     * 格式化数字（添加千分位分隔符）
     * @param number 数字
     * @return 格式化后的字符串（如：1,234,567）
     */
    fun formatNumber(number: Number): String
    
    /**
     * 手机号脱敏（如：138****5678）
     * @param phone 手机号
     * @return 脱敏后的手机号
     */
    fun maskPhone(phone: String?): String?
    
    /**
     * 邮箱脱敏（如：abc***@example.com）
     * @param email 邮箱
     * @return 脱敏后的邮箱
     */
    fun maskEmail(email: String?): String?
    
    /**
     * 验证手机号格式
     * @param phone 手机号
     * @return 是否有效
     */
    fun isValidPhone(phone: String?): Boolean
    
    /**
     * 验证邮箱格式
     * @param email 邮箱
     * @return 是否有效
     */
    fun isValidEmail(email: String?): Boolean
    
    /**
     * 验证身份证格式
     * @param idCard 身份证号
     * @return 是否有效
     */
    fun isValidIdCard(idCard: String?): Boolean
}

/**
 * IUtil 接口的实现类
 * 在同一个文件中实现所有工具方法
 */
object UtilImpl : IUtil {
    
    // ==================== 时间处理 ====================
    
    override fun formatTime(timestamp: Long, pattern: String): String {
        return try {
            val sdf = java.text.SimpleDateFormat(pattern, java.util.Locale.getDefault())
            sdf.format(java.util.Date(timestamp))
        } catch (e: Exception) {
            ""
        }
    }
    
    override fun parseTime(timeString: String, pattern: String): Long? {
        return try {
            val sdf = java.text.SimpleDateFormat(pattern, java.util.Locale.getDefault())
            sdf.parse(timeString)?.time
        } catch (e: Exception) {
            null
        }
    }
    
    override fun getCurrentTimeMillis(): Long {
        return System.currentTimeMillis()
    }
    
    override fun formatCurrentTime(pattern: String): String {
        return formatTime(getCurrentTimeMillis(), pattern)
    }
    
    override fun formatDate(timestamp: Long, pattern: String): String {
        return formatTime(timestamp, pattern)
    }
    
    override fun getRelativeTime(timestamp: Long): String {
        val now = getCurrentTimeMillis()
        val diff = now - timestamp
        
        return when {
            diff < 60 * 1000 -> "刚刚"
            diff < 60 * 60 * 1000 -> "${diff / (60 * 1000)}分钟前"
            diff < 24 * 60 * 60 * 1000 -> "${diff / (60 * 60 * 1000)}小时前"
            diff < 2 * 24 * 60 * 60 * 1000 -> "昨天"
            diff < 7 * 24 * 60 * 60 * 1000 -> "${diff / (24 * 60 * 60 * 1000)}天前"
            else -> formatTime(timestamp, "yyyy-MM-dd")
        }
    }
    
    // ==================== 字符串处理 ====================
    
    override fun encryptString(data: String): String {
        // 简单实现：Base64编码（实际项目中应使用AES等加密算法）
        return base64Encode(data)
    }
    
    override fun decryptString(data: String): String {
        // 简单实现：Base64解码（实际项目中应使用AES等加密算法）
        return base64Decode(data) ?: ""
    }
    
    override fun md5(data: String): String {
        return try {
            val md = java.security.MessageDigest.getInstance("MD5")
            val bytes = md.digest(data.toByteArray())
            bytes.joinToString("") { "%02x".format(it) }
        } catch (e: Exception) {
            ""
        }
    }
    
    override fun base64Encode(data: String): String {
        return try {
            android.util.Base64.encodeToString(data.toByteArray(Charsets.UTF_8), android.util.Base64.NO_WRAP)
        } catch (e: Exception) {
            ""
        }
    }
    
    override fun base64Decode(data: String): String? {
        return try {
            val bytes = android.util.Base64.decode(data, android.util.Base64.NO_WRAP)
            String(bytes, Charsets.UTF_8)
        } catch (e: Exception) {
            null
        }
    }
    
    override fun urlEncode(data: String): String {
        return try {
            java.net.URLEncoder.encode(data, "UTF-8")
        } catch (e: Exception) {
            data
        }
    }
    
    override fun urlDecode(data: String): String? {
        return try {
            java.net.URLDecoder.decode(data, "UTF-8")
        } catch (e: Exception) {
            null
        }
    }
    
    override fun isEmpty(str: String?): Boolean {
        return str.isNullOrBlank()
    }
    
    override fun isNotEmpty(str: String?): Boolean {
        return !isEmpty(str)
    }
    
    override fun trim(str: String?): String? {
        return str?.trim()
    }
    
    override fun substring(str: String, start: Int, end: Int): String? {
        return try {
            if (start < 0 || end > str.length || start > end) {
                null
            } else {
                str.substring(start, end)
            }
        } catch (e: Exception) {
            null
        }
    }
    
    // ==================== 数据转换 ====================
    
    override fun <T> toJson(obj: T): String {
        return try {
            com.google.gson.Gson().toJson(obj)
        } catch (e: Exception) {
            ""
        }
    }
    
    override fun <T> fromJson(json: String, clazz: Class<T>): T? {
        return try {
            com.google.gson.Gson().fromJson(json, clazz)
        } catch (e: Exception) {
            null
        }
    }
    
    @Suppress("UNCHECKED_CAST")
    override fun <T> fromJson(json: String, typeToken: Any): T? {
        return try {
            val gson = com.google.gson.Gson()
            val type = (typeToken as com.google.gson.reflect.TypeToken<*>).type
            gson.fromJson<T>(json, type)
        } catch (e: Exception) {
            null
        }
    }
    
    override fun numberToString(number: Number?): String {
        return number?.toString() ?: ""
    }
    
    override fun stringToInt(str: String?, defaultValue: Int): Int {
        return try {
            str?.toInt() ?: defaultValue
        } catch (e: Exception) {
            defaultValue
        }
    }
    
    override fun stringToLong(str: String?, defaultValue: Long): Long {
        return try {
            str?.toLong() ?: defaultValue
        } catch (e: Exception) {
            defaultValue
        }
    }
    
    override fun stringToFloat(str: String?, defaultValue: Float): Float {
        return try {
            str?.toFloat() ?: defaultValue
        } catch (e: Exception) {
            defaultValue
        }
    }
    
    override fun stringToDouble(str: String?, defaultValue: Double): Double {
        return try {
            str?.toDouble() ?: defaultValue
        } catch (e: Exception) {
            defaultValue
        }
    }
    
    override fun stringToBoolean(str: String?, defaultValue: Boolean): Boolean {
        return try {
            str?.toBoolean() ?: defaultValue
        } catch (e: Exception) {
            defaultValue
        }
    }
    
    // ==================== 设备信息 ====================
    
    override fun getScreenWidth(context: Context): Int {
        return context.resources.displayMetrics.widthPixels
    }
    
    override fun getScreenHeight(context: Context): Int {
        return context.resources.displayMetrics.heightPixels
    }
    
    override fun getStatusBarHeight(context: Context): Int {
        var result = 0
        val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
        if (resourceId > 0) {
            result = context.resources.getDimensionPixelSize(resourceId)
        }
        return result
    }
    
    override fun getNavigationBarHeight(context: Context): Int {
        var result = 0
        val resourceId = context.resources.getIdentifier("navigation_bar_height", "dimen", "android")
        if (resourceId > 0) {
            result = context.resources.getDimensionPixelSize(resourceId)
        }
        return result
    }
    
    override fun getDeviceId(context: Context): String {
        return try {
            android.provider.Settings.Secure.getString(context.contentResolver, android.provider.Settings.Secure.ANDROID_ID) ?: ""
        } catch (e: Exception) {
            ""
        }
    }
    
    override fun getAppVersionName(context: Context): String {
        return try {
            val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
            packageInfo.versionName ?: ""
        } catch (e: Exception) {
            ""
        }
    }
    
    override fun getAppVersionCode(context: Context): Int {
        return try {
            val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
            @Suppress("DEPRECATION")
            packageInfo.versionCode
        } catch (e: Exception) {
            0
        }
    }
    
    override fun getPackageName(context: Context): String {
        return context.packageName
    }
    
    // ==================== 单位转换 ====================
    
    override fun dpToPx(context: Context, dp: Float): Int {
        val density = context.resources.displayMetrics.density
        return (dp * density + 0.5f).toInt()
    }
    
    override fun pxToDp(context: Context, px: Float): Float {
        val density = context.resources.displayMetrics.density
        return px / density
    }
    
    override fun spToPx(context: Context, sp: Float): Int {
        return android.util.TypedValue.applyDimension(
            android.util.TypedValue.COMPLEX_UNIT_SP,
            sp,
            context.resources.displayMetrics
        ).toInt()
    }
    
    override fun pxToSp(context: Context, px: Float): Float {
        return px / context.resources.displayMetrics.scaledDensity
    }
    
    // ==================== 文件操作 ====================
    
    override fun readFile(filePath: String, charset: String): String? {
        return try {
            val file = java.io.File(filePath)
            if (file.exists() && file.isFile) {
                file.readText(java.nio.charset.Charset.forName(charset))
            } else {
                null
            }
        } catch (e: Exception) {
            null
        }
    }
    
    override fun writeFile(filePath: String, content: String, charset: String, append: Boolean): Boolean {
        return try {
            val file = java.io.File(filePath)
            file.parentFile?.mkdirs()
            file.writeText(content, java.nio.charset.Charset.forName(charset))
            true
        } catch (e: Exception) {
            false
        }
    }
    
    override fun readFileBytes(filePath: String): ByteArray? {
        return try {
            val file = java.io.File(filePath)
            if (file.exists() && file.isFile) {
                file.readBytes()
            } else {
                null
            }
        } catch (e: Exception) {
            null
        }
    }
    
    override fun writeFileBytes(filePath: String, bytes: ByteArray, append: Boolean): Boolean {
        return try {
            val file = java.io.File(filePath)
            file.parentFile?.mkdirs()
            if (append && file.exists()) {
                file.appendBytes(bytes)
            } else {
                file.writeBytes(bytes)
            }
            true
        } catch (e: Exception) {
            false
        }
    }
    
    override fun deleteFile(filePath: String): Boolean {
        return try {
            val file = java.io.File(filePath)
            file.delete()
        } catch (e: Exception) {
            false
        }
    }
    
    override fun fileExists(filePath: String): Boolean {
        return try {
            val file = java.io.File(filePath)
            file.exists() && file.isFile
        } catch (e: Exception) {
            false
        }
    }
    
    override fun getFileSize(filePath: String): Long {
        return try {
            val file = java.io.File(filePath)
            if (file.exists() && file.isFile) {
                file.length()
            } else {
                -1
            }
        } catch (e: Exception) {
            -1
        }
    }
    
    override fun copyFile(srcPath: String, destPath: String): Boolean {
        return try {
            val srcFile = java.io.File(srcPath)
            val destFile = java.io.File(destPath)
            if (!srcFile.exists() || !srcFile.isFile) {
                return false
            }
            destFile.parentFile?.mkdirs()
            srcFile.copyTo(destFile, overwrite = true)
            true
        } catch (e: Exception) {
            false
        }
    }
    
    // ==================== 其他工具方法 ====================
    
    override fun getRandomString(length: Int, includeNumbers: Boolean, includeLetters: Boolean): String {
        val chars = buildString {
            if (includeNumbers) append("0123456789")
            if (includeLetters) append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
        }
        if (chars.isEmpty()) return ""
        
        return (1..length)
            .map { chars.random() }
            .joinToString("")
    }
    
    override fun getRandomInt(min: Int, max: Int): Int {
        return (min..max).random()
    }
    
    override fun formatFileSize(size: Long): String {
        return when {
            size < 1024 -> "$size B"
            size < 1024 * 1024 -> String.format("%.2f KB", size / 1024.0)
            size < 1024 * 1024 * 1024 -> String.format("%.2f MB", size / (1024.0 * 1024.0))
            else -> String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0))
        }
    }
    
    override fun formatNumber(number: Number): String {
        return java.text.NumberFormat.getNumberInstance(java.util.Locale.getDefault()).format(number)
    }
    
    override fun maskPhone(phone: String?): String? {
        if (phone.isNullOrEmpty()) return phone
        return if (phone.length >= 7) {
            "${phone.substring(0, 3)}****${phone.substring(phone.length - 4)}"
        } else {
            phone
        }
    }
    
    override fun maskEmail(email: String?): String? {
        if (email.isNullOrEmpty()) return email
        val atIndex = email.indexOf('@')
        return if (atIndex > 0) {
            val prefix = email.substring(0, atIndex)
            val suffix = email.substring(atIndex)
            if (prefix.length > 3) {
                "${prefix.substring(0, 3)}***$suffix"
            } else {
                "$prefix***$suffix"
            }
        } else {
            email
        }
    }
    
    override fun isValidPhone(phone: String?): Boolean {
        if (phone.isNullOrEmpty()) return false
        // 中国手机号：1开头，11位数字
        val pattern = "^1[3-9]\\d{9}$"
        return java.util.regex.Pattern.matches(pattern, phone)
    }
    
    override fun isValidEmail(email: String?): Boolean {
        if (email.isNullOrEmpty()) return false
        val pattern = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
        return java.util.regex.Pattern.matches(pattern, email)
    }
    
    override fun isValidIdCard(idCard: String?): Boolean {
        if (idCard.isNullOrEmpty()) return false
        // 18位身份证号
        val pattern18 = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$"
        // 15位身份证号
        val pattern15 = "^[1-9]\\d{5}\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}$"
        return java.util.regex.Pattern.matches(pattern18, idCard) || 
               java.util.regex.Pattern.matches(pattern15, idCard)
    }
}

