import BackendEnvironmentClient
import AppSessionCountClient
import ComponentLibrary
import ComposableArchitecture
import SwiftUI

// swiftlint:disable file_length

struct DebugMenuPanelView: View {
    @Bindable var store: StoreOf<DebugMenu>

    init(store: StoreOf<DebugMenu>) {
        self.store = store
        self.handleIconSize = handleIconSize
        self.isMetricsAutoScrollOn = isMetricsAutoScrollOn
    }

    @State var handleIconSize: CGSize = .zero
    @State var isMetricsAutoScrollOn: Bool = true

    var body: some View {
        ZStack {
            if store.isMinimized {
                minimizedView
                    .background {
                        VisualEffectView(style: .dark)
                    }
                    .clipShape(.rect(cornerRadius: Constants.panelCornerRadius))
                    .offset(x: store.offsetX - store.panelWidth.halved + Constants.precalculatedHalfMiniWidth,
                            y: store.offsetY - store.panelHeight.halved + Constants.precalculatedHalfMiniHeight)
            } else {
                ZStack {
                    Color.clear
                    expandedView
                }
                .background {
                    VisualEffectView(style: .dark)
                }
                .clipShape(.rect(cornerRadius: Constants.panelCornerRadius))
                .frame(width: store.panelWidth, height: store.panelHeight)
                .offset(x: store.offsetX, y: store.offsetY)
            }
        }
    }
}

private extension DebugMenuPanelView {
    enum Constants {
        static let editingTitleCopy: String = "Editing"
        static let clearUnsavedButtonCopy: String = "Clear Unsaved"
        static let triangleSymbolName: String = "righttriangle.fill"
        static let buttonCopyClearLog: String = "Clear Log"
        static let buttonCopy: String = "Clear Log"
        static let buttonCopyAutoScrollOn = "AutoScroll On"
        static let buttonCopyAutoScrollOff = "AutoScroll Off"
        static let buttonCopySave: String = "Save"
        static let debugTitleString: String = "Debug"
        static let bugSymbolName: String = "ant"
        static let xMarkSymbolName: String = "xmark"
        static let lastScorllItemID: String = "last_scroll_item"
        static let chevronSymbolIconName: String = "chevron.down"
        static let contextBarVerticalHeight: CGFloat = 52.0
        static let contextButtonHeight: CGFloat = 32.0
        static let contextButtonHorizontalPadding: CGFloat = 16.0
        static let contextPaddingOnAllSides: CGFloat = 8.0
        static let contextButtonTextFontSize: CGFloat = 12.0
        static let mcontextButtonStrokeWidth: CGFloat = 2.0
        static let internalHorizontalPadding: CGFloat = 16.0
        static let bugSymbolFontSize: CGFloat = 16.0
        static let panelCornerRadius: CGFloat = 6.0
        static let panelBarHorizontalPadding: CGFloat = 8.0
        static let panelSelectorPadding: CGFloat = 6.0
        static let backgroundOpacity: CGFloat = 0.5
        static let xMarkFontSize: CGFloat = 16.0
        static let precalculatedHalfMiniWidth: CGFloat = 25.5
        static let precalculatedHalfMiniHeight: CGFloat = 22.5
        static let bufferSpaceOnScrollView: CGFloat = 4.0
        static let lowFocusTextOpacity: CGFloat = 0.8
        static let panelBarFontSize: CGFloat = 10.0
        static let overlayOpacity: CGFloat = 0.35
        static let titleBarHeight: CGFloat = 45.0
        static let titleFontSize: CGFloat = 12.0
        static let titleLeadingPadding: CGFloat = 12.0
        static let titleTrailingPadding: CGFloat = 8.0
        static let handleSpacing: CGFloat = 3.0
        static let handleOffset: CGFloat = 4.0
        static let handleFontSize: CGFloat = 24.0
    }

    @ViewBuilder
    var expandedView: some View {
        VStack {
            titleBar

            ZStack {
                switch store.panelType {
                case .trackedMetrics:
                    metricBars

                case .appSessions:
                    appSessionsView

                case .featureToggles, .appStorage:
                    Color.clear

                case .environment:
                    environmentPanel

                case .onDeviceFileExplorer:
                    onDeviceFileExplorer

                case .panelSelector:
                    panelSelectorList

                case .fileViewerPanel:
                    fileViewerPanel

                case .internalViews, .reportBug, .flex:
                    EmptyView()
                }

                VStack {
                    Spacer()
                    HStack {
                        Spacer()
                        resizeHandle
                    }
                }
            }
        }
    }

    @ViewBuilder
    var resizeHandle: some View {
        ZStack {
            Image(systemName: Constants.triangleSymbolName)
                .offset(x: .zero, y: .zero)

            Image(systemName: Constants.triangleSymbolName)
                .offset(x: Constants.handleSpacing, y: Constants.handleSpacing)

            Image(systemName: Constants.triangleSymbolName)
                .offset(x: Constants.handleSpacing.doubled, y: Constants.handleSpacing.doubled)

            Image(systemName: Constants.triangleSymbolName)
                .offset(x: Constants.handleSpacing.tripled, y: Constants.handleSpacing.tripled)
        }
        .font(.system(size: Constants.handleFontSize, weight: .regular))
        .foregroundStyle(.white.opacity(.oneTenth))
        .contentShape(.rect)
        .offset(x: Constants.handleOffset, y: Constants.handleOffset)
        .gesture(DragGesture()
            .onChanged { event in
                store.send(.onResize(event.translation))
            }
        )
    }

    @ViewBuilder
    var minimizedView: some View {
        HStack {
            handleAndIcon
        }
        .debugTitleBarStyle()
    }

    @ViewBuilder
    var environmentPanel: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Backend Environment")
                .font(.system(.title3, design: .rounded).weight(.semibold))

            Text("Switching environments will sign you out and restart the app.")
                .font(.footnote)
                .foregroundStyle(.secondary)

            VStack(spacing: 12) {
                ForEach(BackendEnvironment.allCases, id: \.self) { environment in
                    Button {
                        store.send(.environmentButtonTapped(environment))
                    } label: {
                        HStack {
                            Image(systemName: store.currentEnvironment == environment ? "checkmark.circle.fill" : "circle")
                                .foregroundStyle(store.currentEnvironment == environment ? Color.accentColor : Color.secondary)

                            Text(environment.displayName)
                                .font(.body)

                            Spacer()

                            if environment == .production {
                                Text("default")
                                    .font(.caption)
                                    .foregroundStyle(.secondary)
                            }
                    }
                    .padding(.vertical, 8)
                    .padding(.horizontal, 12)
                    .background(
                        RoundedRectangle(cornerRadius: 12)
                            .fill(store.currentEnvironment == environment ? Color.accentColor.opacity(0.1) : Color.secondary.opacity(0.08))
                    )
                }
                .buttonStyle(.plain)
                .disabled(store.currentEnvironment == environment)
            }
        }
        }
        .padding(16)
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    @ViewBuilder
    var titleBar: some View {
        HStack {
            handleAndIcon
            Text(Constants.debugTitleString)
                .typographyV1(.headline5.neueMontrealMedium())
            Spacer()
            panelSelector
            Button {
                store.send(.closePanel(animated: true))
            } label: {
                Image(systemName: Constants.xMarkSymbolName)
                    .font(.system(size: Constants.xMarkFontSize, weight: .bold))
            }
        }
        .debugTitleBarStyle()
    }

    @ViewBuilder
    var handleAndIcon: some View {
        HStack {
            MoveHandle()
                .contentShape(.rect)
                .gesture(DragGesture()
                    .onChanged { event in
                        store.send(.onDrag(event.translation))
                    }
                )
            Button {
                store.send(.toggleExpansion)
            } label: {
                Image(systemName: Constants.bugSymbolName)
                    .font(.system(size: Constants.bugSymbolFontSize))
            }
        }
    }

    @ViewBuilder
    var metricBars: some View {
        VStack(spacing: .zero) {
            let lastScrollItemID = Constants.lastScorllItemID
            ScrollView(showsIndicators: false) {
                ScrollViewReader { scrollProxy in
                    LazyVStack {
                        scrollBufferSpace

                        ForEach(store.trackedMetricsEvents) { event in
                            MetricsBar(
                                id: event.id.uuidString,
                                title: event.name,
                                subTitle: event.actionName,
                                contextTitle: event.formattedDate,
                                description: event.propertiesAsString
                            )
                        }
                        scrollBufferSpace
                            .id(lastScrollItemID)
                    }
                    .padding(.horizontal, Constants.panelBarHorizontalPadding)
                    .onChange(of: store.trackedMetricsEvents.count) { _, _ in
                        guard isMetricsAutoScrollOn else { return }
                        scrollProxy.scrollTo(lastScrollItemID, anchor: .bottom)
                    }
                }
            }

            HStack {
                Button {
                    isMetricsAutoScrollOn = !isMetricsAutoScrollOn
                } label: {
                    Text(isMetricsAutoScrollOn ? Constants.buttonCopyAutoScrollOn : Constants.buttonCopyAutoScrollOff)
                        .contextButtonStyle(isFilled: isMetricsAutoScrollOn, accentColor: .blue)
                }

                Button {
                    store.send(.clearAnalyticsEvents)
                } label: {
                    Text(Constants.buttonCopyClearLog)
                        .contextButtonStyle(isFilled: false, accentColor: .blue)
                }

                Spacer()
            }
            .padding(Constants.contextPaddingOnAllSides)
            .frame(height: Constants.contextBarVerticalHeight)
            .background { blackBackgroundOverlay }
        }
    }

    @ViewBuilder
    var appSessionsView: some View {
        VStack(spacing: .zero) {
            ScrollView(showsIndicators: false) {
                LazyVStack {
                    scrollBufferSpace

                    // App Session Data Section
                    VStack(alignment: .leading, spacing: 8) {
                        HStack {
                            Text("App Session Data")
                                .font(.headline)
                                .foregroundColor(.white)
                            Spacer()
                            Button {
                                store.send(.resetAppSessions)
                            } label: {
                                Image(systemName: "arrow.clockwise")
                                    .font(.system(size: 12, weight: .medium))
                                    .foregroundColor(.blue)
                            }
                        }

                        SessionDataCard(
                            sessionData: store.appSessionData,
                            selectedUserForDetails: store.selectedUserForDetails
                        )
                    }
                    .padding()
                    .background(Color.black.opacity(0.3))
                    .cornerRadius(8)
                    .padding(.horizontal, Constants.panelBarHorizontalPadding)

                    scrollBufferSpace
                }
            }

            // Action bar for app sessions
            HStack {
                Button {
                    store.send(.refreshAppSessionData)
                } label: {
                    Text("Refresh")
                        .contextButtonStyle(isFilled: false, accentColor: .blue)
                }

                Button {
                    store.send(.resetAppSessions)
                } label: {
                    Text("Reset")
                        .contextButtonStyle(isFilled: false, accentColor: .red)
                }

                Spacer()
            }
            .padding(Constants.contextPaddingOnAllSides)
            .frame(height: Constants.contextBarVerticalHeight)
            .background { blackBackgroundOverlay }
        }
    }

    @ViewBuilder
    var panelSelectorList: some View {
        ScrollView(showsIndicators: false) {
            LazyVStack {
                scrollBufferSpace
                ForEach(DebugMenuPanelType.selectableTypes) { panelType in
                    DebugPanelTypeSelectorBar(
                        viewModel: .init(
                            panelType: panelType,
                            onTap: {
                                store.send(.selectedPanel(panelType))
                            }
                        )
                    )
                }
            }
            .padding(.horizontal, Constants.panelBarHorizontalPadding)
        }
    }

    @ViewBuilder
    var onDeviceFileExplorer: some View {
        ZStack {
            Color.clear
            VStack(spacing: .zero) {
                ScrollView {
                    LazyVStack(spacing: .zero) {
                        Color.clear
                            .frame(height: 4.0)
                        ForEach(store.onDeviceFileExplorereDataModels) { fileModel in
                            OnDeviceFileExplorerFileBar(
                                systemIcon: fileModel.highLevelFileType.icon,
                                displayName: fileModel.lastComponent,
                                isDirectory: fileModel.isDirectory
                            ) {
                                if fileModel.isDirectory {
                                    store.send(.selectedDirectoryOnFileExplorer(fileModel))
                                } else {
                                    store.send(.selectedDocumentOnFileExplorer(fileModel))
                                }
                            }
                            .padding(.bottom, 4.0)
                        }
                    }
                    .padding(.horizontal, 8.0)
                    .padding(.trailing, 8.0)
                }
                fileExplorerActionSaveBar
            }
        }
    }

    @ViewBuilder
    var fileExplorerActionSaveBar: some View {
        HStack {
            if !store.onDeviceFileExplorerPathSelections.isEmpty {
                Button {
                    store.send(.backUpOneDirectory)
                } label: {
                    Image(systemName: "arrow.turn.left.up")
                        .font(.system(size: 12.0))
                        .foregroundStyle(.white)
                        .padding(.all, 8.0)
                        .padding(.horizontal, 4.0)
                        .background {
                            Color.blue
                        }
                        .clipShape(.rect(cornerRadius: .infinity))
                }
            }

            Spacer()

            Button {
                switch store.onDeviceFileExplorerRootDirectory {
                case .cache:
                    store.send(.selectedRootDirectory(.documents))
                case .documents:
                    store.send(.selectedRootDirectory(.cache))
                }
            } label: {
                Text(store.onDeviceFileExplorerRootDirectory.displayString)
                    .font(.system(size: 12.0))
                    .foregroundStyle(.white)
                    .padding(.all, 8.0)
                    .padding(.horizontal, 4.0)
                    .background {
                        Color.blue.opacity(0.5)
                    }
                    .clipShape(.rect(cornerRadius: .infinity))
            }

            Text("/")
                .font(.system(size: 12.0))
                .foregroundStyle(.blue.opacity(0.25))

            Text(store.onDeviceFileExplorerPathSelections.joined(separator: " / "))
                .font(.system(size: 12.0))
                .foregroundStyle(.blue)
                .padding(.trailing, 16.0)
        }
        .padding(.horizontal, Constants.panelBarHorizontalPadding)
        .frame(height: Constants.contextBarVerticalHeight)
        .background { blackBackgroundOverlay }
    }

    @ViewBuilder
    var fileViewerPanel: some View {
        ZStack {
            Color.clear
            VStack(spacing: .zero) {
                if let fileDataModel = store.onDeviceFileExplorerFileSelection {
                    DebugFileViewerPanel(fileDataModel: fileDataModel)
                } else {
                    EmptyView()
                }

                fileViewerPanelBar
            }
        }
    }

    @ViewBuilder
    var fileViewerPanelBar: some View {
        HStack {
            Button {
                store.send(.exitFileViewer)
            } label: {
                Image(systemName: "arrow.left")
                    .font(.system(size: 12.0, weight: .bold))
                    .foregroundStyle(.white)
                    .padding(.all, 8.0)
                    .padding(.horizontal, 4.0)
                    .background {
                        Color.blue
                    }
                    .clipShape(.rect(cornerRadius: .infinity))
            }

            Spacer()
        }
        .padding(.horizontal, Constants.panelBarHorizontalPadding)
        .frame(height: Constants.contextBarVerticalHeight)
        .background { blackBackgroundOverlay }
    }

    @ViewBuilder
    var panelSelector: some View {
        ZStack {
            if store.panelType.showsPanelSelector {
                Button {
                    store.send(.openPanelSelector)
                } label: {
                    HStack {
                        Image(systemName: store.panelType.iconName)
                            .font(.system(size: Constants.panelBarFontSize, weight: .medium))
                            .foregroundStyle(store.panelType.iconColor)

                        Text(store.panelType.displayTitle)
                            .typographyV1(.body1.neueMontrealMedium())
                            .foregroundStyle(.white.opacity(Constants.lowFocusTextOpacity))

                        Image(systemName: Constants.chevronSymbolIconName)
                            .font(.system(size: Constants.panelBarFontSize, weight: .medium))
                            .foregroundStyle(.white.opacity(.half))
                    }
                    .padding(Constants.panelSelectorPadding)
                    .padding(.horizontal, Constants.panelBarHorizontalPadding)
                    .background {
                        Color.black.opacity(.half)
                    }
                    .clipShape(.rect(cornerRadius: .infinity))
                }
            } else {
                EmptyView()
            }
        }
    }

    struct _ContextButtonStyleModifier: ViewModifier {
        let isFilled: Bool
        let fillStrokeColor: Color

        func body(content: Content) -> some View {
            content
                .font(.system(size: Constants.contextButtonTextFontSize, weight: .medium))
                .foregroundStyle(.white.opacity(Constants.lowFocusTextOpacity))
                .padding(.horizontal, Constants.internalHorizontalPadding)
                .frame(height: Constants.contextButtonHeight)
                .background {
                    if isFilled {
                        RoundedRectangle(cornerRadius: .infinity)
                            .fill(fillStrokeColor)
                    } else {
                        RoundedRectangle(cornerRadius: .infinity)
                            .stroke(fillStrokeColor, lineWidth: Constants.mcontextButtonStrokeWidth)
                    }
                }
        }
    }

    struct _TitleBarStyleModifier: ViewModifier {
        func body(content: Content) -> some View {
            content
                .padding(.leading, Constants.titleLeadingPadding)
                .padding(.trailing, Constants.titleTrailingPadding)
                .frame(height: Constants.titleBarHeight)
                .foregroundStyle(.white.opacity(Constants.lowFocusTextOpacity))
                .background {
                    Color.black.opacity(.half)
                }
        }
    }

    @ViewBuilder
    var scrollBufferSpace: some View {
        Color.clear.frame(height: Constants.bufferSpaceOnScrollView)
    }

    @ViewBuilder
    var blackBackgroundOverlay: some View {
        Color.black.opacity(Constants.backgroundOpacity)
    }
}

// MARK: - Session Data Card

private struct SessionDataCard: View {
    let sessionData: AppSessionData
    let selectedUserForDetails: String?

    var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            // Overall Metrics
            Text("📊 Overall Stats")
                .font(.caption)
                .foregroundColor(.orange)
                .padding(.bottom, 2)

            SessionDataRow(label: "Total Sessions", value: "\(sessionData.totalSessions)")
            SessionDataRow(label: "Cold Start", value: "\(sessionData.coldStartSessions)")
            SessionDataRow(label: "Refocus", value: "\(sessionData.refocusSessions)")

            Divider()
                .background(Color.gray.opacity(0.5))
                .padding(.vertical, 4)

            // Authentication Metrics
            Text("🔐 Authentication Stats")
                .font(.caption)
                .foregroundColor(.green)
                .padding(.bottom, 2)

            SessionDataRow(label: "Authenticated", value: "\(sessionData.authenticatedSessions)")
            SessionDataRow(label: "Unauthenticated", value: "\(sessionData.unauthenticatedSessions)")
            SessionDataRow(label: "Unique Users", value: "\(sessionData.totalUniqueAuthenticatedUsers)")
            SessionDataRow(label: "First-Time Logins", value: "\(sessionData.firstTimeLoginSessions)")
            SessionDataRow(label: "Auth Transitions", value: "\(sessionData.sessionsWithAuthTransitions)")

            Divider()
                .background(Color.gray.opacity(0.5))
                .padding(.vertical, 4)

            // Analytics Insights
            Text("📈 Insights")
                .font(.caption)
                .foregroundColor(.purple)
                .padding(.bottom, 2)

            let avgSessionsPerUser = sessionData.authenticatedSessions / max(1, sessionData.totalUniqueAuthenticatedUsers)
            SessionDataRow(label: "Avg Sessions/User", value: "\(avgSessionsPerUser)")

            let coldStartRatio = sessionData.totalSessions > 0 ?
                Double(sessionData.coldStartSessions) / Double(sessionData.totalSessions) : 0.0
            SessionDataRow(label: "Cold Start Ratio", value: String(format: "%.1f%%", coldStartRatio * 100))

            let transitionRate = sessionData.totalSessions > 0 ?
                Double(sessionData.sessionsWithAuthTransitions) / Double(sessionData.totalSessions) : 0.0
            SessionDataRow(label: "Transition Rate", value: String(format: "%.1f%%", transitionRate * 100))

            let firstTimeRate = sessionData.totalSessions > 0 ?
                Double(sessionData.firstTimeLoginSessions) / Double(sessionData.totalSessions) : 0.0
            SessionDataRow(label: "New User Rate", value: String(format: "%.1f%%", firstTimeRate * 100))
        }
    }

    private func formatDate(_ date: Date) -> String {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        return formatter.string(from: date)
    }
}

private struct SessionDataRow: View {
    let label: String
    let value: String
    let isIndented: Bool

    init(label: String, value: String, isIndented: Bool = false) {
        self.label = label
        self.value = value
        self.isIndented = isIndented
    }

    var body: some View {
        HStack {
            Text(label)
                .font(.system(size: isIndented ? 10 : 12, weight: .regular))
                .foregroundColor(isIndented ? .gray : .white)
            Spacer()
            Text(value)
                .font(.system(size: isIndented ? 10 : 12, weight: .medium))
                .foregroundColor(isIndented ? .gray : .cyan)
        }
    }
}

private extension View {
    func debugTitleBarStyle() -> some View {
        self.modifier(DebugMenuPanelView._TitleBarStyleModifier())
    }

    func contextButtonStyle(isFilled: Bool = true, accentColor: Color) -> some View {
        self.modifier(DebugMenuPanelView._ContextButtonStyleModifier(isFilled: isFilled, fillStrokeColor: accentColor))
    }
}
