import XCTest
@testable import TencentQianWebViewSDK

/// `DownloadResponseHandler.isDownloadable` 纯函数单测。
///
/// 覆盖:
/// - MIME 白名单命中(PDF / Office / 压缩包 / octet-stream)
/// - Content-Disposition: attachment 触发
/// - 普通 HTML / JSON 等不触发
/// - 大小写不敏感
/// - 空 MIME + 无 Content-Disposition → 不触发
final class DownloadResponseHandlerTests: XCTestCase {

    // MARK: - 辅助

    /// 构造一个带指定 MIME 和 Content-Disposition 的 HTTPURLResponse
    private func makeHTTPResponse(
        url: String = "https://example.com/file",
        mimeType: String? = nil,
        headers: [String: String] = [:]
    ) -> HTTPURLResponse {
        HTTPURLResponse(
            url: URL(string: url)!,
            statusCode: 200,
            httpVersion: "HTTP/1.1",
            headerFields: headers
        )!
    }

    /// 构造一个只有 mimeType 的 URLResponse(非 HTTP)
    private func makeURLResponse(
        url: String = "https://example.com/file",
        mimeType: String? = nil
    ) -> URLResponse {
        URLResponse(
            url: URL(string: url)!,
            mimeType: mimeType,
            expectedContentLength: -1,
            textEncodingName: nil
        )
    }

    // MARK: - MIME 白名单命中

    func test_pdf_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/pdf")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_docx_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_xlsx_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_pptx_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_legacy_doc_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/msword")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_legacy_xls_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/vnd.ms-excel")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_legacy_ppt_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/vnd.ms-powerpoint")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_zip_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/zip")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_x_zip_compressed_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/x-zip-compressed")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_octet_stream_mime_is_downloadable() {
        let resp = makeURLResponse(mimeType: "application/octet-stream")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    // MARK: - MIME 大小写不敏感

    func test_mime_matching_is_case_insensitive() {
        let resp = makeURLResponse(mimeType: "Application/PDF")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_mime_mixed_case_zip() {
        let resp = makeURLResponse(mimeType: "Application/Zip")
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    // MARK: - Content-Disposition: attachment

    func test_content_disposition_attachment_triggers_download() {
        let resp = makeHTTPResponse(headers: ["Content-Disposition": "attachment; filename=\"report.pdf\""])
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_content_disposition_attachment_case_insensitive() {
        let resp = makeHTTPResponse(headers: ["Content-Disposition": "ATTACHMENT; filename=\"x.zip\""])
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_content_disposition_inline_does_not_trigger() {
        let resp = makeHTTPResponse(headers: ["Content-Disposition": "inline"])
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }

    // MARK: - 不触发的 MIME

    func test_html_mime_is_not_downloadable() {
        let resp = makeURLResponse(mimeType: "text/html")
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_json_mime_is_not_downloadable() {
        let resp = makeURLResponse(mimeType: "application/json")
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_plain_text_is_not_downloadable() {
        let resp = makeURLResponse(mimeType: "text/plain")
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_image_png_is_not_downloadable() {
        let resp = makeURLResponse(mimeType: "image/png")
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }

    // MARK: - 边界

    func test_nil_mime_no_headers_is_downloadable_due_to_system_default() {
        // 注意:iOS 的 URLResponse 在 mimeType 传入 nil 时,
        // 系统可能将其默认为 "application/octet-stream",该 MIME 在白名单中。
        // 这是 iOS 平台行为,isDownloadable 返回 true 是正确的。
        let resp = makeURLResponse(mimeType: nil)
        XCTAssertTrue(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_empty_mime_is_not_downloadable() {
        let resp = makeURLResponse(mimeType: "")
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }

    func test_non_http_response_without_matching_mime_is_not_downloadable() {
        // URLResponse(非 HTTP)没有 Content-Disposition header,只看 MIME
        let resp = makeURLResponse(mimeType: "text/css")
        XCTAssertFalse(DownloadResponseHandler.isDownloadable(response: resp))
    }
}
