package de.softwareapp_hb.privateqrscanner.util

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.provider.CalendarContract
import android.provider.ContactsContract
import android.provider.ContactsContract.CommonDataKinds.StructuredName
import android.provider.ContactsContract.CommonDataKinds.Organization
import android.provider.Settings
import androidx.core.net.toUri

object Intents {
    fun openUrl(context: Context, url: String) {
        val intent = Intent(Intent.ACTION_VIEW, url.toUri()).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    fun shareText(context: Context, text: String) {
        shareContent(context, text, "text/plain")
    }

    fun shareContent(context: Context, text: String, mimeType: String) {
        val intent = Intent(Intent.ACTION_SEND)
            .setType(mimeType)
            .putExtra(Intent.EXTRA_TEXT, text)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        val chooser = Intent.createChooser(intent, null).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(chooser)
    }

    fun dialPhone(context: Context, number: String) {
        val intent = Intent(Intent.ACTION_DIAL, "tel:${number.trim()}".toUri())
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    @Suppress("SpellCheckingInspection")
    fun sendSms(context: Context, number: String, message: String?) {
        val base = number.trim()
        val intent = Intent(Intent.ACTION_SENDTO, "smsto:$base".toUri())
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        if (!message.isNullOrBlank()) {
            intent.putExtra("sms_body", message)
        }
        context.startActivity(intent)
    }

    fun sendEmail(context: Context, email: String, subject: String?, body: String? = null) {
        val intent = Intent(Intent.ACTION_SENDTO, "mailto:${email.trim()}".toUri())
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        if (!subject.isNullOrBlank()) {
            intent.putExtra(Intent.EXTRA_SUBJECT, subject)
        }
        if (!body.isNullOrBlank()) {
            intent.putExtra(Intent.EXTRA_TEXT, body)
        }
        context.startActivity(intent)
    }

    fun openWifiSettings(context: Context) {
        val intent = Intent(Settings.ACTION_WIFI_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    fun addContact(context: Context, parsed: ParsedContact?, rawContent: String) {
        val intent = buildAddContactIntent(parsed, rawContent)
        context.startActivity(intent)
    }

    internal fun buildAddContactIntent(parsed: ParsedContact?, rawContent: String): Intent {
        return Intent(Intent.ACTION_INSERT).apply {
            type = ContactsContract.Contacts.CONTENT_TYPE
            val fullName = parsed?.fullName
                ?.let(::normalizeContactNameForInsert)
                ?.takeIf { it.isNotBlank() }
            val givenName = parsed?.givenName?.trim().takeIf { !it.isNullOrBlank() }
            val familyName = parsed?.familyName?.trim().takeIf { !it.isNullOrBlank() }
            val company = parsed?.organization?.trim().takeIf { !it.isNullOrBlank() }
            val jobTitle = parsed?.title?.trim().takeIf { !it.isNullOrBlank() }
            val note = parsed?.note?.trim().takeIf { !it.isNullOrBlank() }

            if (givenName == null && familyName == null) {
                fullName?.let { putExtra(ContactsContract.Intents.Insert.NAME, it) }
            }
            company?.let {
                // Some OEM contacts apps honor one key but not the other.
                putExtra(ContactsContract.Intents.Insert.COMPANY, it)
                putExtra(Organization.COMPANY, it)
            }
            jobTitle?.let {
                putExtra(ContactsContract.Intents.Insert.JOB_TITLE, it)
                putExtra(Organization.TITLE, it)
            }
            parsed?.phones?.firstOrNull()?.let { putExtra(ContactsContract.Intents.Insert.PHONE, it) }
            parsed?.emails?.firstOrNull()?.let { putExtra(ContactsContract.Intents.Insert.EMAIL, it) }
            parsed?.address?.let { putExtra(ContactsContract.Intents.Insert.POSTAL, it) }

            if (!note.isNullOrBlank()) {
                putExtra(ContactsContract.Intents.Insert.NOTES, note)
            }
            if (parsed == null) {
                putExtra(ContactsContract.Intents.Insert.NOTES, rawContent)
            }

            if (givenName != null || familyName != null) {
                val dataRows = ArrayList<ContentValues>()
                val structuredName = ContentValues().apply {
                    put(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
                    givenName?.let { put(StructuredName.GIVEN_NAME, it) }
                    familyName?.let { put(StructuredName.FAMILY_NAME, it) }
                    fullName?.let { put(StructuredName.DISPLAY_NAME, it) }
                }
                dataRows.add(structuredName)
                putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, dataRows)
            }
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
    }

    private fun normalizeContactNameForInsert(rawName: String): String {
        val tokens = rawName.trim()
            .split(Regex("\\s+"))
            .filter { it.isNotBlank() }
            .toMutableList()
        if (tokens.size >= 2) {
            val last = tokens[tokens.lastIndex]
            val beforeLast = tokens[tokens.lastIndex - 1]
            if (last.equals(beforeLast, ignoreCase = true)) {
                tokens.removeAt(tokens.lastIndex)
            }
        }
        return tokens.joinToString(" ")
    }

    fun addCalendarEvent(context: Context, parsed: ParsedCalendarEvent?, rawContent: String) {
        val intent = Intent(Intent.ACTION_INSERT).apply {
            data = CalendarContract.Events.CONTENT_URI
            putExtra(CalendarContract.Events.TITLE, parsed?.title ?: "Scanned event")
            putExtra(CalendarContract.Events.DESCRIPTION, parsed?.description ?: rawContent)
            parsed?.location?.let { putExtra(CalendarContract.Events.EVENT_LOCATION, it) }
            parsed?.startMillis?.let { putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, it) }
            parsed?.endMillis?.let { putExtra(CalendarContract.EXTRA_EVENT_END_TIME, it) }
            if (parsed?.allDay == true) {
                putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true)
            }
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        context.startActivity(intent)
    }
}
