//
//  WiredTransferPhotoStore.swift
//  suixinkan
//
//  Created by Codex on 2026/6/29.
//

import Foundation

/// 有线传图本地记录仓库，按相册与用户维度持久化到 UserDefaults。
final class WiredTransferPhotoStore {
    private let defaults: UserDefaults
    private let accountPrefixProvider: () -> String
    private let userIDProvider: () -> String

    private static let keyPrefix = "wired_transfer_photos_"
    private static let deletedSuffix = "_deleted"
    private static let bindingsSuffix = "_photo_bindings"
    private static let transferModeKeySuffix = "wired_transfer_mode_option"
    static let modeLiveCapture = "边拍边传"
    static let modePostShootTransfer = "拍后传输"

    /// 读取缓存的传输模式选项。
    func loadTransferModeOption() -> String? {
        let value = defaults.string(forKey: transferModeKey())?
            .trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        switch value {
        case Self.modeLiveCapture, Self.modePostShootTransfer:
            return value
        default:
            return nil
        }
    }

    /// 缓存传输模式选项。
    func saveTransferModeOption(_ option: String) {
        switch option {
        case Self.modeLiveCapture, Self.modePostShootTransfer:
            defaults.set(option, forKey: transferModeKey())
        default:
            break
        }
    }

    /// 初始化仓库，注入账号前缀与用户 ID 提供者。
    init(
        defaults: UserDefaults = .standard,
        accountPrefixProvider: @escaping () -> String,
        userIDProvider: @escaping () -> String
    ) {
        self.defaults = defaults
        self.accountPrefixProvider = accountPrefixProvider
        self.userIDProvider = userIDProvider
    }

    /// 查询照片绑定的相册 ID。
    func albumID(forPhoto photoID: String) -> Int? {
        guard !photoID.isEmpty else { return nil }
        return loadBindings().first { $0.photoID == photoID }?.albumID
    }

    /// 绑定照片到相册。
    func bindPhotoToAlbum(photoID: String, albumID: Int) {
        guard !photoID.isEmpty, albumID > 0, !userIDProvider().isEmpty else { return }
        var bindings = loadBindings().filter { $0.photoID != photoID }
        bindings.append(PhotoAlbumBinding(photoID: photoID, albumID: albumID))
        saveBindings(bindings)
    }

    /// 加载已删除照片 ID。
    func loadDeletedIDs(albumID: Int) -> Set<String> {
        guard albumID > 0, !userIDProvider().isEmpty else { return [] }
        let ids = defaults.stringArray(forKey: deletedKey(albumID)) ?? []
        return Set(ids)
    }

    /// 加载相册下的传图记录。
    func load(albumID: Int) -> [WiredTransferPhotoRecord] {
        guard albumID > 0 else { return [] }
        let userID = userIDProvider()
        guard !userID.isEmpty else { return [] }

        let deletedIDs = loadDeletedIDs(albumID: albumID)
        guard let data = defaults.data(forKey: storageKey(albumID)),
              let records = try? JSONDecoder().decode([WiredTransferPhotoRecord].self, from: data)
        else { return [] }

        let filteredRecords = records.filter { record in
            !deletedIDs.contains(record.id)
                && record.userId == userID
                && record.albumId == albumID
        }

        let normalizedRecords = filteredRecords.map { $0.normalizeInterruptedTransfer() }
        return normalizedRecords
            .filter(\.isDisplayable)
            .sorted { $0.capturedAt > $1.capturedAt }
            .also { items in
                items.forEach { bindPhotoToAlbum(photoID: $0.id, albumID: albumID) }
            }
    }

    /// 保存相册传图记录。
    func save(albumID: Int, records: [WiredTransferPhotoRecord]) {
        guard albumID > 0 else { return }
        let userID = userIDProvider()
        guard !userID.isEmpty else { return }

        let normalized = records
            .filter { $0.userId == userID && $0.albumId == albumID }
            .sorted { $0.capturedAt > $1.capturedAt }
        normalized.forEach { bindPhotoToAlbum(photoID: $0.id, albumID: albumID) }

        if let data = try? JSONEncoder().encode(normalized) {
            defaults.set(data, forKey: storageKey(albumID))
        }
    }

    /// 标记并移除单张照片。
    func remove(albumID: Int, photoID: String) {
        guard albumID > 0, !photoID.isEmpty else { return }
        markDeleted(albumID: albumID, photoID: photoID)
        let deletedIDs = loadDeletedIDs(albumID: albumID)
        guard let data = defaults.data(forKey: storageKey(albumID)),
              var records = try? JSONDecoder().decode([WiredTransferPhotoRecord].self, from: data)
        else { return }
        records
            .filter { $0.id == photoID && $0.userId == userIDProvider() && $0.albumId == albumID }
            .forEach { deleteRecordFiles($0) }
        records = records.filter { record in
            !deletedIDs.contains(record.id)
                && record.userId == userIDProvider()
                && record.albumId == albumID
        }
        save(albumID: albumID, records: records)
    }

    /// 标记照片已删除。
    func markDeleted(albumID: Int, photoID: String) {
        guard albumID > 0, !photoID.isEmpty, !userIDProvider().isEmpty else { return }
        let updated = loadDeletedIDs(albumID: albumID).union([photoID])
        defaults.set(Array(updated), forKey: deletedKey(albumID))
    }

    /// 清空相册关联的本地缓存。
    func clearAlbum(albumID: Int) -> Set<String> {
        guard albumID > 0 else { return [] }
        let userID = userIDProvider()
        guard !userID.isEmpty else { return [] }

        guard let data = defaults.data(forKey: storageKey(albumID)),
              let records = try? JSONDecoder().decode([WiredTransferPhotoRecord].self, from: data)
        else {
            CameraDownloadStorage.removeScopeDirectory(for: downloadScope(albumID: albumID))
            defaults.removeObject(forKey: storageKey(albumID))
            defaults.removeObject(forKey: deletedKey(albumID))
            return []
        }

        let userRecords = records.filter { $0.userId == userID }
        userRecords.forEach { deleteRecordFiles($0) }
        CameraDownloadStorage.removeScopeDirectory(for: downloadScope(albumID: albumID))

        let bindings = loadBindings().filter { $0.albumID != albumID }
        saveBindings(bindings)

        defaults.removeObject(forKey: storageKey(albumID))
        defaults.removeObject(forKey: deletedKey(albumID))

        return Set(userRecords.map(\.id))
    }

    private func deleteRecordFiles(_ record: WiredTransferPhotoRecord) {
        deleteFileIfExists(record.localPath)
        deleteFileIfExists(record.thumbnailPath)
    }

    private func deleteFileIfExists(_ path: String) {
        guard !path.isEmpty else { return }
        guard let url = CameraDownloadStorage.resolveLocalURL(from: path) else { return }
        if FileManager.default.fileExists(atPath: url.path) {
            try? FileManager.default.removeItem(at: url)
        }
    }

    private func storageKey(_ albumID: Int) -> String {
        "\(accountPrefixProvider())\(Self.keyPrefix)\(albumID)"
    }

    private func deletedKey(_ albumID: Int) -> String {
        "\(storageKey(albumID))\(Self.deletedSuffix)"
    }

    private func bindingsKey() -> String {
        "\(accountPrefixProvider())\(Self.bindingsSuffix)"
    }

    private func transferModeKey() -> String {
        "\(accountPrefixProvider())\(Self.transferModeKeySuffix)"
    }

    private func downloadScope(albumID: Int) -> CameraDownloadStorage.Scope {
        CameraDownloadStorage.Scope(accountKey: accountPrefixProvider(), albumID: albumID)
    }

    private struct PhotoAlbumBinding: Codable {
        let photoID: String
        let albumID: Int
    }

    private func loadBindings() -> [PhotoAlbumBinding] {
        guard let data = defaults.data(forKey: bindingsKey()),
              let bindings = try? JSONDecoder().decode([PhotoAlbumBinding].self, from: data)
        else { return [] }
        return bindings
    }

    private func saveBindings(_ bindings: [PhotoAlbumBinding]) {
        if let data = try? JSONEncoder().encode(bindings) {
            defaults.set(data, forKey: bindingsKey())
        }
    }
}

private extension WiredTransferPhotoRecord {
    var isDisplayable: Bool {
        if !remoteURL.isEmpty { return true }
        if let url = CameraDownloadStorage.resolveLocalURL(from: localPath),
           FileManager.default.fileExists(atPath: url.path) {
            return true
        }
        if let url = CameraDownloadStorage.resolveLocalURL(from: thumbnailPath),
           FileManager.default.fileExists(atPath: url.path) {
            return true
        }
        return false
    }

    func normalizeInterruptedTransfer() -> WiredTransferPhotoRecord {
        guard status == WiredTransferUploadStatus.transferring.rawValue
            || status == WiredTransferUploadStatus.uploading.rawValue
        else { return self }

        var copy = self
        copy = WiredTransferPhotoRecord(
            id: id,
            sourceId: sourceId,
            fileName: fileName,
            localPath: localPath,
            thumbnailPath: thumbnailPath,
            capturedAt: capturedAt,
            fileSizeBytes: fileSizeBytes,
            status: remoteURL.isEmpty ? WiredTransferUploadStatus.pending.rawValue : WiredTransferUploadStatus.uploaded.rawValue,
            progress: remoteURL.isEmpty ? 0 : 100,
            errorMessage: errorMessage,
            albumId: albumId,
            userId: userId,
            remoteURL: remoteURL,
            updatedAt: updatedAt
        )
        return copy
    }
}

private extension Array {
    @discardableResult
    func also(_ body: (Self) -> Void) -> Self {
        body(self)
        return self
    }
}
