import SwiftUI
import OSLog
import UIKit

// periphery:ignore
private let logger = Logger(subsystem: AppIdentifiers.subsystem, category: "RemoteFileView")

enum SessionFileFullScreenContentBuilder {
    static func content(
        text: String,
        filePath: String,
        workspaceID: String?,
        serverBaseURL: URL?,
        workspaceHostMount: String?,
        fetchSessionFileData: ((String) async throws -> Data)?,
        sessionID: String
    ) -> FullScreenCodeContent {
        let displayPath = filePath.workspaceRelativePath(hostMount: workspaceHostMount) ?? filePath

        guard let workspaceID,
              let serverBaseURL,
              let fetchSessionFileData else {
            return .fromText(text, filePath: filePath)
        }

        return .fromText(
            text,
            filePath: displayPath,
            workspaceContext: .init(
                workspaceID: workspaceID,
                serverBaseURL: serverBaseURL,
                fetchWorkspaceFile: { _, path in
                    try await fetchSessionFileData(path)
                },
                sessionID: sessionID,
                fetchSessionFile: nil
            )
        )
    }
}

/// Fetches and displays a file from the session's working directory.
///
/// Triggered when the user taps a file path in a tool call header.
/// Reuses `FileContentView` for rendering — same syntax highlighting,
/// markdown, JSON, images as inline tool output.
// periphery:ignore
struct RemoteFileView: View {
    let workspaceId: String
    let sessionId: String
    let path: String

    @Environment(\.apiClient) private var apiClient
    @Environment(SessionStore.self) private var sessionStore
    @Environment(WorkspaceStore.self) private var workspaceStore
    @Environment(\.dismiss) private var dismiss
    @Environment(\.reviewCommentSelectionScope) private var reviewCommentSelectionScope
    @State private var content: String?
    @State private var imageData: Data?
    @State private var videoSource: AuthenticatedMediaSource?
    @State private var isLoading = true
    @State private var errorMessage: String?
    @State private var loadedServerBaseURL: URL?
    @State private var fetchSessionFileData: ((String) async throws -> Data)?
    @State private var resolvedWorkspaceId: String?
    @State private var screenHeight: CGFloat = 0

    private var resolvedScreenHeight: CGFloat {
        let height = screenHeight
        return (height.isFinite && height > 0) ? height : 800
    }

    private var filename: String {
        (path as NSString).lastPathComponent
    }

    private var pathExtension: String {
        (path as NSString).pathExtension.lowercased()
    }

    private var detectedFileType: FileType {
        FileType.detect(from: path)
    }

    private var viewerDismissButton: some View {
        Button {
            dismiss()
        } label: {
            Image(systemName: FullScreenViewerNavigationChrome.DismissMode.modal.systemImageName)
        }
        .accessibilityLabel(FullScreenViewerNavigationChrome.DismissMode.modal.accessibilityLabel)
    }

    private var isImagePath: Bool {
        if case .image = detectedFileType {
            return true
        }
        return pathExtension == "svg"
    }

    private var isVideoPath: Bool {
        if case .video = detectedFileType {
            return true
        }
        return false
    }

    private var currentWorkspaceHostMount: String? {
        let targetWorkspaceId = resolvedWorkspaceId ?? (workspaceId.isEmpty ? nil : workspaceId)
        guard let targetWorkspaceId else { return nil }

        if let activeServerId = workspaceStore.activeServerId,
           let workspace = workspaceStore.workspacesByServer[activeServerId]?
           .first(where: { $0.id == targetWorkspaceId }) {
            return workspace.hostMount
        }

        return workspaceStore.workspaces.first(where: { $0.id == targetWorkspaceId })?.hostMount
    }

    private func fullScreenContent(text: String) -> FullScreenCodeContent {
        SessionFileFullScreenContentBuilder.content(
            text: text,
            filePath: path,
            workspaceID: resolvedWorkspaceId,
            serverBaseURL: loadedServerBaseURL,
            workspaceHostMount: currentWorkspaceHostMount,
            fetchSessionFileData: fetchSessionFileData,
            sessionID: sessionId
        )
    }

    var body: some View {
        Group {
            if let content {
                // Text content: use the canonical full-screen viewer (same as timeline).
                // The VC has its own nav controller with dismiss, copy, share, toggle.
                FullScreenCodeView(
                    content: fullScreenContent(text: content),
                    reviewCommentSelectionContext: reviewCommentSelectionScope?.makeContext(
                        sessionId: sessionId,
                        sourceLabel: filename,
                        filePath: path
                    )
                )
            } else if let imageData, isImagePath {
                NavigationStack {
                    ScrollView {
                        DataImagePreviewView(
                            data: imageData,
                            mimeType: MediaMimeType.imageMimeType(forPathExtension: pathExtension),
                            maxPixelSize: 2_400,
                            heightMode: .unrestricted
                        )
                        .padding()
                    }
                    .background(Color.themeBg)
                    .navigationTitle(filename)
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .topBarLeading) {
                            viewerDismissButton
                        }
                    }
                }
            } else if let videoSource, isVideoPath {
                NavigationStack {
                    AuthenticatedMediaPlayerView(
                        source: videoSource,
                        height: min(max(resolvedScreenHeight * 0.34, 220), 420),
                        unavailableTitle: "Video preview unavailable",
                        unavailableSystemImage: "film.slash"
                    )
                    .padding(.horizontal, 16)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color.themeBgDark)
                    .navigationTitle(filename)
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .topBarLeading) {
                            viewerDismissButton
                        }
                    }
                }
            } else {
                NavigationStack {
                    Group {
                        if isLoading {
                            ProgressView("Loading \(filename)…")
                                .frame(maxWidth: .infinity, maxHeight: .infinity)
                        } else if let errorMessage {
                            VStack(spacing: 12) {
                                Image(systemName: "exclamationmark.triangle")
                                    .font(.title)
                                    .foregroundStyle(.themeRed)
                                Text(errorMessage)
                                    .font(.subheadline)
                                    .foregroundStyle(.themeComment)
                                    .multilineTextAlignment(.center)
                            }
                            .padding()
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                        }
                    }
                    .background(Color.themeBg)
                    .navigationTitle(filename)
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .topBarLeading) {
                            viewerDismissButton
                        }
                    }
                }
            }
        }
        .background {
            WindowScreenHeightProbe { height in
                guard abs(height - screenHeight) > 0.5 else { return }
                screenHeight = height
            }
        }
        .task {
            await loadFile()
        }
    }

    private func loadFile() async {
        guard let api = apiClient else {
            errorMessage = "Not connected to server"
            isLoading = false
            return
        }

        let resolvedWorkspaceId: String
        if !workspaceId.isEmpty {
            resolvedWorkspaceId = workspaceId
        } else if let cachedWorkspaceId = sessionStore.workspaceId(for: sessionId),
                  !cachedWorkspaceId.isEmpty {
            resolvedWorkspaceId = cachedWorkspaceId
        } else {
            errorMessage = "Missing workspace context for this session"
            isLoading = false
            return
        }

        loadedServerBaseURL = api.baseURL
        self.resolvedWorkspaceId = resolvedWorkspaceId
        let workspaceHostMount = currentWorkspaceHostMount
        fetchSessionFileData = { [api, resolvedWorkspaceId, sessionId] filePath in
            let previewPath = filePath.workspaceRelativePath(hostMount: workspaceHostMount) ?? filePath
            return try await api.getSessionFileData(
                workspaceId: resolvedWorkspaceId,
                sessionId: sessionId,
                path: previewPath
            )
        }
        let previewPath = path.workspaceRelativePath(hostMount: workspaceHostMount) ?? path

        do {
            if isImagePath {
                let data = try await api.getSessionFileData(
                    workspaceId: resolvedWorkspaceId,
                    sessionId: sessionId,
                    path: previewPath
                )
                self.imageData = data
            } else if isVideoPath {
                self.videoSource = try await api.makeSessionFileMediaSource(
                    workspaceId: resolvedWorkspaceId,
                    sessionId: sessionId,
                    path: previewPath,
                    contentTypeHint: MediaMimeType.videoMimeType(forPathExtension: pathExtension),
                    sourceFileExtension: pathExtension
                )
            } else {
                let text = try await api.getSessionFile(
                    workspaceId: resolvedWorkspaceId,
                    sessionId: sessionId,
                    path: previewPath
                )
                self.content = text
            }
        } catch {
            logger.error("Failed to load file \(path): \(error.localizedDescription)")
            errorMessage = error.localizedDescription
        }

        isLoading = false
    }
}

private struct WindowScreenHeightProbe: UIViewRepresentable {
    let onChange: (CGFloat) -> Void

    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: .zero)
        view.isUserInteractionEnabled = false
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        DispatchQueue.main.async {
            let height = uiView.window?.windowScene?.screen.bounds.height ?? uiView.bounds.height
            guard height.isFinite, height > 0 else { return }
            onChange(height)
        }
    }
}
