import SwiftUI
import ComposeApp

/// A SwiftUI view that loads images from authenticated API endpoints.
/// Use this for media that requires auth token (documents, completions, etc.)
///
/// Example usage:
/// ```swift
/// AuthenticatedImage(mediaURL: document.mediaUrl)
/// AuthenticatedImage(mediaURL: completion.images[0].mediaUrl, contentMode: .fill)
/// ```
struct AuthenticatedImage: View {
    let mediaURL: String?
    var contentMode: ContentMode = .fit
    var placeholder: AnyView = AnyView(
        ProgressView()
            .tint(Color.appPrimary)
    )
    var errorView: AnyView = AnyView(
        VStack(spacing: 8) {
            Image(systemName: "photo")
                .font(.system(size: 40))
                .foregroundColor(Color.appTextSecondary)
            Text("Failed to load")
                .font(.caption)
                .foregroundColor(Color.appTextSecondary)
        }
    )

    @StateObject private var loader = AuthenticatedImageLoader()

    var body: some View {
        Group {
            switch loader.state {
            case .idle, .loading:
                placeholder
            case .success(let image):
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: contentMode)
                    .accessibilityLabel("Image")
            case .failure:
                errorView
            }
        }
        .onAppear {
            loader.load(mediaURL: mediaURL)
        }
        .onChange(of: mediaURL) { _, newURL in
            loader.load(mediaURL: newURL)
        }
    }
}

// MARK: - Convenience initializers

extension AuthenticatedImage {
    /// Initialize with just the media URL path
    init(mediaURL: String?) {
        self.mediaURL = mediaURL
    }

    /// Initialize with media URL and content mode
    init(mediaURL: String?, contentMode: ContentMode) {
        self.mediaURL = mediaURL
        self.contentMode = contentMode
    }

    /// Clear the in-memory image cache (call on logout to free memory and avoid stale data)
    static func clearCache() {
        AuthenticatedImageLoader.clearCache()
    }
}

// MARK: - Image Loader

private enum ImageLoadState {
    case idle
    case loading
    case success(UIImage)
    case failure(Error)
}

@MainActor
private class AuthenticatedImageLoader: ObservableObject {
    @Published private(set) var state: ImageLoadState = .idle

    private var currentTask: Task<Void, Never>?
    private var currentURL: String?

    // In-memory cache for loaded images
    private static var imageCache: NSCache<NSString, UIImage> = {
        let cache = NSCache<NSString, UIImage>()
        cache.countLimit = 100
        cache.totalCostLimit = 50 * 1024 * 1024 // 50 MB
        return cache
    }()

    private static let memoryWarningObserver: NSObjectProtocol = {
        NotificationCenter.default.addObserver(
            forName: UIApplication.didReceiveMemoryWarningNotification,
            object: nil,
            queue: .main
        ) { _ in
            imageCache.removeAllObjects()
        }
    }()

    func load(mediaURL: String?) {
        _ = Self.memoryWarningObserver

        guard let mediaURL = mediaURL, !mediaURL.isEmpty else {
            state = .failure(NSError(domain: "AuthenticatedImage", code: -1, userInfo: [NSLocalizedDescriptionKey: "No URL provided"]))
            return
        }

        // Skip if already loading the same URL
        if currentURL == mediaURL {
            return
        }
        currentURL = mediaURL

        // Check cache first
        if let cachedImage = Self.imageCache.object(forKey: mediaURL as NSString) {
            state = .success(cachedImage)
            return
        }

        // Cancel any existing task
        currentTask?.cancel()

        state = .loading

        currentTask = Task {
            await loadImage(mediaURL: mediaURL)
        }
    }

    private func loadImage(mediaURL: String) async {
        // Get auth token
        guard let token = TokenStorage.shared.getToken() else {
            state = .failure(NSError(domain: "AuthenticatedImage", code: 401, userInfo: [NSLocalizedDescriptionKey: "Not authenticated"]))
            return
        }

        // Build full URL using the media base URL (without /api suffix)
        // Media URLs from the API are like "/api/media/document/123"
        let baseURL = ApiClient.shared.getMediaBaseUrl()
        let fullURL = baseURL + mediaURL

        guard let url = URL(string: fullURL) else {
            state = .failure(NSError(domain: "AuthenticatedImage", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(fullURL)"]))
            return
        }

        // Create request with auth header
        var request = URLRequest(url: url)
        request.setValue("Token \(token)", forHTTPHeaderField: "Authorization")
        request.timeoutInterval = 15
        request.cachePolicy = .returnCacheDataElseLoad

        do {
            let (data, response) = try await URLSession.shared.data(for: request)

            // Check for task cancellation
            if Task.isCancelled { return }

            // Validate response
            if let httpResponse = response as? HTTPURLResponse {
                guard (200...299).contains(httpResponse.statusCode) else {
                    state = .failure(NSError(domain: "AuthenticatedImage", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: "HTTP \(httpResponse.statusCode)"]))
                    return
                }
            }

            // Convert to UIImage
            guard let image = UIImage(data: data) else {
                state = .failure(NSError(domain: "AuthenticatedImage", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid image data"]))
                return
            }

            // Cache the image
            Self.imageCache.setObject(image, forKey: mediaURL as NSString)

            state = .success(image)

        } catch {
            if !Task.isCancelled {
                state = .failure(error)
            }
        }
    }

    /// Clear the image cache (call on logout)
    static func clearCache() {
        imageCache.removeAllObjects()
    }
}

// MARK: - Preview

#Preview {
    VStack(spacing: 20) {
        // Loading state
        AuthenticatedImage(mediaURL: nil)
            .frame(width: 200, height: 200)
            .background(Color.appBackgroundSecondary)
            .cornerRadius(12)

        Text("AuthenticatedImage Preview")
            .font(.headline)
    }
    .padding()
}
