package com.a2i.forwarder.core

import com.a2i.forwarder.A2iApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.util.Base64
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory

/**
 * SMTP 直连发送纯文本邮件（SMTPS/隐式 TLS，端口 465）。
 * 在 [Dispatchers.IO] 上执行，不阻塞主线程。
 */
object EmailSender {
    suspend fun send(
        host: String, port: Int, user: String, password: String,
        from: String, to: String, subject: String, body: String,
    ): Result<Unit> = withContext(Dispatchers.IO) {
        runCatching {
            val factory = SSLSocketFactory.getDefault()
            // 隐式 TLS：直接通过 SSLSocketFactory 创建 SSLSocket 连接 SMTP 服务器（推荐端口 465）
            val ssl = factory.createSocket(host, port) as SSLSocket
            ssl.soTimeout = 15_000
            ssl.startHandshake()
            val reader: BufferedReader = ssl.inputStream.bufferedReader()
            val writer: BufferedWriter = ssl.outputStream.bufferedWriter()

            fun read(): String = reader.readLine() ?: error("连接关闭")
            fun cmd(c: String) { writer.write("$c\r\n"); writer.flush() }

            fun expectEhlo(): String {
                cmd("EHLO a2i")
                var last = ""
                do { last = read() } while (last.startsWith("250-"))
                if (!last.startsWith("250 ")) error("EHLO: $last")
                return last
            }

            var r = read()
            if (!r.startsWith("220")) error("SMTP: $r")
            expectEhlo()

            if (user.isNotBlank() && password.isNotBlank()) {
                cmd("AUTH LOGIN")
                r = read()
                if (!r.startsWith("334")) error("AUTH: $r")
                cmd(Base64.getEncoder().encodeToString(user.toByteArray()))
                r = read()
                if (!r.startsWith("334")) error("AUTH user: $r")
                cmd(Base64.getEncoder().encodeToString(password.toByteArray()))
                r = read()
                if (!r.startsWith("235")) error("AUTH pass: $r")
            }

            cmd("MAIL FROM:<$from>")
            r = read()
            if (!r.startsWith("250")) error("FROM: $r")

            cmd("RCPT TO:<$to>")
            r = read()
            if (!r.startsWith("250")) error("TO: $r")

            cmd("DATA")
            r = read()
            if (!r.startsWith("354")) error("DATA: $r")

            writer.write(buildMime(from, to, subject, body))
            writer.write("\r\n.\r\n")
            writer.flush()
            r = read()
            if (!r.startsWith("250")) error("SEND: $r")

            cmd("QUIT")
            runCatching { ssl.close() }
            Unit
        }
    }

    private fun buildMime(from: String, to: String, subject: String, body: String): String {
        val subjB64 = Base64.getEncoder().encodeToString(subject.toByteArray(Charsets.UTF_8))
        val bodyB64 = Base64.getEncoder().encodeToString(body.toByteArray(Charsets.UTF_8))
        return buildString {
            append("From: <$from>\r\n")
            append("To: <$to>\r\n")
            append("Subject: =?UTF-8?B?$subjB64?=\r\n")
            append("MIME-Version: 1.0\r\n")
            append("Content-Type: text/plain; charset=UTF-8\r\n")
            append("Content-Transfer-Encoding: base64\r\n")
            append("\r\n")
            append(bodyB64)
        }
    }

    /** 如果电邮转发已启用且收件人非空，异步发邮件（fire-and-forget，不阻塞主流程）。 */
    fun trySend(app: A2iApp, title: String, body: String, scope: CoroutineScope) {
        val s = app.settings
        if (!s.emailForwardingEnabled.value || s.emailTo.value.isBlank()) return
        scope.launch {
            EmailSender.send(s.smtpHost.value, s.smtpPort.value, s.smtpUser.value, s.smtpPassword.value,
                s.smtpFrom.value, s.emailTo.value, title, body)
        }
    }
}