//
//  WeChatShareServiceTests.swift
//  suixinkanTests
//

import UIKit
import WechatOpenSDK
import XCTest
@testable import suixinkan

/// 微信分享服务测试。
@MainActor
final class WeChatShareServiceTests: XCTestCase {
    /// 测试 Universal Link 必须是 HTTPS 且以 `/` 结尾。
    func testUniversalLinkMustUseHTTPSAndEndWithSlash() {
        XCTAssertTrue(WeChatConfig.validateUniversalLink(WeChatConfig.universalLink))
        XCTAssertFalse(WeChatConfig.validateUniversalLink("https://www.zhifly.cn/suixinkan"))
        XCTAssertFalse(WeChatConfig.validateUniversalLink("http://www.zhifly.cn/suixinkan/"))
    }

    /// 测试分享场景映射到微信 SDK scene 值。
    func testShareSceneMapsToWXValues() {
        XCTAssertEqual(WeChatShareScene.session.wxSceneValue, 0)
        XCTAssertEqual(WeChatShareScene.timeline.wxSceneValue, 1)
        XCTAssertEqual(WeChatShareScene.favorite.wxSceneValue, 2)
    }

    /// 测试小程序版本映射到微信 SDK 值。
    func testMiniProgramTypeMapsToWXValues() {
        XCTAssertEqual(WeChatMiniProgramType.release.rawValue, 0)
        XCTAssertEqual(WeChatMiniProgramType.test.rawValue, 1)
        XCTAssertEqual(WeChatMiniProgramType.preview.rawValue, 2)
    }

    /// 测试 Debug 包使用体验版小程序，Release 包保持传入版本。
    func testMiniProgramTypeResolvesForCurrentBuild() {
        #if DEBUG
        XCTAssertEqual(WeChatMiniProgramType.release.resolvedForCurrentBuild, .preview)
        XCTAssertEqual(WeChatMiniProgramType.test.resolvedForCurrentBuild, .preview)
        #else
        XCTAssertEqual(WeChatMiniProgramType.release.resolvedForCurrentBuild, .release)
        XCTAssertEqual(WeChatMiniProgramType.test.resolvedForCurrentBuild, .test)
        #endif
    }

    /// 测试微信错误码解析。
    func testShareResultFromWXErrorCode() {
        XCTAssertEqual(WeChatShareResult.fromWXErrorCode(0), .success)
        XCTAssertEqual(WeChatShareResult.fromWXErrorCode(-2), .cancelled)
        XCTAssertEqual(WeChatShareResult.fromWXErrorCode(99), .unknown(99))
    }

    /// 测试缩略图压缩到微信限制内。
    func testThumbImageProcessorKeepsDataUnderLimit() throws {
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: 640, height: 640))
        let image = renderer.image { context in
            UIColor.systemBlue.setFill()
            context.fill(CGRect(x: 0, y: 0, width: 640, height: 640))
            UIColor.white.setFill()
            context.fill(CGRect(x: 80, y: 80, width: 480, height: 480))
        }

        let thumbData = try XCTUnwrap(WeChatThumbImageProcessor.makeThumbData(from: image))
        XCTAssertLessThanOrEqual(thumbData.count, WeChatThumbImageProcessor.maxThumbBytes)
    }

    /// 测试小程序高清预览图压缩到微信限制内。
    func testMiniProgramHDImageProcessorKeepsDataUnderLimit() throws {
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: 1200, height: 800))
        let image = renderer.image { context in
            UIColor.systemGreen.setFill()
            context.fill(CGRect(x: 0, y: 0, width: 1200, height: 800))
            UIColor.white.setFill()
            context.fill(CGRect(x: 160, y: 120, width: 880, height: 560))
            UIColor.systemBlue.setFill()
            context.fill(CGRect(x: 260, y: 220, width: 680, height: 360))
        }

        let imageData = try XCTUnwrap(WeChatThumbImageProcessor.makeMiniProgramHDImageData(from: image))
        XCTAssertLessThanOrEqual(imageData.count, WeChatThumbImageProcessor.maxMiniProgramHDImageBytes)
        XCTAssertNil(WeChatThumbImageProcessor.makeMiniProgramHDImageData(from: image, maxBytes: 0))
    }

    /// 测试空标题和空链接会直接返回参数错误。
    func testShareWebPageRejectsInvalidPayloadBeforeSending() {
        var results: [WeChatShareResult] = []
        WeChatShareService.shareWebPage(
            WeChatWebPageSharePayload(title: " ", description: "desc", url: "https://example.com"),
            scene: .session
        ) { result in
            results.append(result)
        }
        WeChatShareService.shareWebPage(
            WeChatWebPageSharePayload(title: "title", description: "desc", url: " "),
            scene: .session
        ) { result in
            results.append(result)
        }

        XCTAssertEqual(results, [
            .invalidPayload("分享标题不能为空"),
            .invalidPayload("分享链接不能为空"),
        ])
    }

    /// 测试小程序分享请求字段填充。
    func testMakeMiniProgramRequestFillsWXObject() throws {
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: 600, height: 400))
        let image = renderer.image { context in
            UIColor.systemOrange.setFill()
            context.fill(CGRect(x: 0, y: 0, width: 600, height: 400))
        }
        let payload = WeChatMiniProgramSharePayload(
            title: " 举报详情 ",
            description: "查看处理进度",
            webpageURL: " https://www.zhifly.cn/report/40 ",
            userName: " gh_xxxxxxxx ",
            path: " /pages/report/detail?id=40 ",
            miniProgramType: .preview,
            withShareTicket: true,
            disableForward: true
        )

        let request = try XCTUnwrap(try WeChatShareService.makeMiniProgramRequest(payload, scene: .session, previewImage: image).get())
        let message = try XCTUnwrap(request.message)
        let miniProgramObject = try XCTUnwrap(message.mediaObject as? WXMiniProgramObject)

        XCTAssertFalse(request.bText)
        XCTAssertEqual(request.scene, WeChatShareScene.session.wxSceneValue)
        XCTAssertEqual(message.title, "举报详情")
        XCTAssertEqual(message.description, "查看处理进度")
        XCTAssertEqual(miniProgramObject.webpageUrl, "https://www.zhifly.cn/report/40")
        XCTAssertEqual(miniProgramObject.userName, "gh_xxxxxxxx")
        XCTAssertEqual(miniProgramObject.path, "/pages/report/detail?id=40")
        XCTAssertEqual(miniProgramObject.miniProgramType.rawValue, UInt(WeChatMiniProgramType.preview.resolvedForCurrentBuild.rawValue))
        XCTAssertEqual(miniProgramObject.withShareTicket, true)
        XCTAssertEqual(miniProgramObject.disableForward, true)
        XCTAssertLessThanOrEqual(miniProgramObject.hdImageData?.count ?? 0, WeChatThumbImageProcessor.maxMiniProgramHDImageBytes)
    }

    /// 测试小程序分享参数校验。
    func testMakeMiniProgramRequestRejectsInvalidPayload() {
        let valid = WeChatMiniProgramSharePayload(
            title: "举报详情",
            description: "查看处理进度",
            webpageURL: "https://www.zhifly.cn/report/40",
            userName: "gh_xxxxxxxx"
        )
        let longURL = "https://www.zhifly.cn/" + String(repeating: "a", count: 1025)

        XCTAssertEqual(
            WeChatShareService.makeMiniProgramRequest(valid, scene: .timeline).failure,
            .invalidPayload("小程序仅支持分享到微信好友")
        )
        XCTAssertEqual(
            WeChatShareService.makeMiniProgramRequest(
                WeChatMiniProgramSharePayload(title: " ", description: "", webpageURL: valid.webpageURL, userName: valid.userName),
                scene: .session
            ).failure,
            .invalidPayload("分享标题不能为空")
        )
        XCTAssertEqual(
            WeChatShareService.makeMiniProgramRequest(
                WeChatMiniProgramSharePayload(title: valid.title, description: "", webpageURL: " ", userName: valid.userName),
                scene: .session
            ).failure,
            .invalidPayload("小程序兼容网页链接不能为空")
        )
        XCTAssertEqual(
            WeChatShareService.makeMiniProgramRequest(
                WeChatMiniProgramSharePayload(title: valid.title, description: "", webpageURL: longURL, userName: valid.userName),
                scene: .session
            ).failure,
            .invalidPayload("小程序兼容网页链接不能超过1024字节")
        )
        XCTAssertEqual(
            WeChatShareService.makeMiniProgramRequest(
                WeChatMiniProgramSharePayload(title: valid.title, description: "", webpageURL: valid.webpageURL, userName: " "),
                scene: .session
            ).failure,
            .invalidPayload("小程序原始 ID 不能为空")
        )
    }
}

private extension Result where Success == SendMessageToWXReq, Failure == WeChatShareResult {
    var failure: WeChatShareResult? {
        guard case .failure(let result) = self else { return nil }
        return result
    }
}
