import SwiftUI
import WebKit
import Foundation
import Observation

struct MobileContentView: View {
    @State private var host = MobileTraderHost()
    @State private var didAutostart = false
    @AppStorage("mt_mobile_setup_completed") private var setupCompleted = false
    @AppStorage("mt_mobile_backend_url") private var storedBackendURL = "http://127.0.0.1:8501"
    @AppStorage("mt_mobile_symbol") private var storedSymbol = "AAPL"
    @AppStorage("mt_mobile_interval") private var storedInterval = "1d"
    @AppStorage("mt_mobile_period") private var storedPeriod = "6mo"
    @AppStorage("mt_mobile_max_bars") private var storedMaxBars = 500
    @AppStorage("mt_mobile_drop_live") private var storedDropLive = true
    @AppStorage("mt_mobile_use_body_range") private var storedUseBodyRange = false
    @AppStorage("mt_mobile_volume_filter_enabled") private var storedVolumeFilterEnabled = false
    @AppStorage("mt_mobile_volume_sma_window") private var storedVolumeSMAWindow = 20
    @AppStorage("mt_mobile_volume_multiplier") private var storedVolumeMultiplier = 1.0
    @AppStorage("mt_mobile_gray_fake") private var storedGrayFake = true
    @AppStorage("mt_mobile_hide_market_closed_gaps") private var storedHideMarketClosedGaps = true
    @AppStorage("mt_mobile_enable_auto_refresh") private var storedEnableAutoRefresh = false
    @AppStorage("mt_mobile_refresh_sec") private var storedRefreshSeconds = 60

    @State private var showSetupSheet = false
    @State private var showHelpSheet = false
    @State private var setupDraft = MobileUserSetupPreferences.default
    @State private var setupBackendURL = "http://127.0.0.1:8501"

    var body: some View {
        NavigationStack {
            Group {
                if let url = host.serverURL {
                    MobileWebView(url: url, reloadToken: host.reloadToken)
                } else {
                    launchView
                }
            }
            .navigationTitle("ManeshTrader")
            .toolbar {
                ToolbarItemGroup(placement: .topBarTrailing) {
                    Button("Help") {
                        showHelpSheet = true
                    }

                    Button("Setup") {
                        setupDraft = storedWebPreferences.normalized().setupDefaults
                        setupBackendURL = storedBackendURL
                        showSetupSheet = true
                    }

                    Button("Reload") {
                        _ = syncHostPreferencesFromStorage()
                        host.reloadWebView()
                    }
                    .disabled(host.serverURL == nil)
                }
            }
        }
        .onAppear {
            guard !didAutostart else { return }
            didAutostart = true

            let normalized = syncHostPreferencesFromStorage()
            if !setupCompleted {
                setupDraft = normalized.setupDefaults
                setupBackendURL = storedBackendURL
                showSetupSheet = true
            }
        }
        .sheet(isPresented: $showSetupSheet) {
            setupSheet
        }
        .sheet(isPresented: $showHelpSheet) {
            MobileHelpSheetView()
        }
    }

    private var storedWebPreferences: MobileWebPreferences {
        MobileWebPreferences(
            symbol: storedSymbol,
            interval: storedInterval,
            period: storedPeriod,
            maxBars: storedMaxBars,
            dropLive: storedDropLive,
            useBodyRange: storedUseBodyRange,
            volumeFilterEnabled: storedVolumeFilterEnabled,
            volumeSMAWindow: storedVolumeSMAWindow,
            volumeMultiplier: storedVolumeMultiplier,
            grayFake: storedGrayFake,
            hideMarketClosedGaps: storedHideMarketClosedGaps,
            enableAutoRefresh: storedEnableAutoRefresh,
            refreshSeconds: storedRefreshSeconds
        )
    }

    private var setupSheet: some View {
        NavigationStack {
            Form {
                Section {
                    Text("Connect this app to a reachable ManeshTrader web backend. iOS cannot run the embedded backend executable directly.")
                        .foregroundStyle(.secondary)
                }

                Section("Backend") {
                    TextField("Base URL", text: $setupBackendURL)
                        .textInputAutocapitalization(.never)
                        .autocorrectionDisabled(true)
                        .keyboardType(.URL)
                    Text("Examples: http://192.168.1.10:8501 or https://your-host")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }

                Section("Data Defaults") {
                    TextField("Symbol", text: $setupDraft.symbol)
                        .textInputAutocapitalization(.characters)
                        .autocorrectionDisabled(true)

                    Picker("Timeframe", selection: $setupDraft.timeframe) {
                        ForEach(MobileUserSetupPreferences.timeframeOptions, id: \.self) { option in
                            Text(option).tag(option)
                        }
                    }

                    Picker("Period", selection: $setupDraft.period) {
                        ForEach(MobileUserSetupPreferences.periodOptions, id: \.self) { option in
                            Text(option).tag(option)
                        }
                    }

                    Stepper(value: $setupDraft.maxBars, in: 20...5000, step: 10) {
                        Text("Max bars: \(setupDraft.maxBars)")
                    }
                }

                if let validationMessage = host.validationMessage {
                    Section {
                        Text(validationMessage)
                            .foregroundStyle(.red)
                            .font(.footnote)
                    }
                }
            }
            .navigationTitle("Setup")
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Use Defaults") {
                        applySetup(MobileUserSetupPreferences.default, backendURL: setupBackendURL, markCompleted: true)
                    }
                }

                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        applySetup(setupDraft.normalized(), backendURL: setupBackendURL, markCompleted: true)
                    }
                }
            }
        }
    }

    private func applySetup(_ preferences: MobileUserSetupPreferences, backendURL: String, markCompleted: Bool) {
        let normalizedSetup = preferences.normalized()
        let mergedPreferences = storedWebPreferences
            .applyingSetup(normalizedSetup)
            .normalized()

        storedBackendURL = backendURL.trimmingCharacters(in: .whitespacesAndNewlines)
        writeWebPreferencesToStorage(mergedPreferences)

        host.applyPreferences(mergedPreferences, backendURLString: storedBackendURL)
        host.reloadWebView()

        if markCompleted {
            setupCompleted = true
        }

        if host.serverURL != nil {
            showSetupSheet = false
        }
    }

    @discardableResult
    private func syncHostPreferencesFromStorage() -> MobileWebPreferences {
        let normalized = storedWebPreferences.normalized()
        writeWebPreferencesToStorage(normalized)
        host.applyPreferences(normalized, backendURLString: storedBackendURL)
        return normalized
    }

    private func writeWebPreferencesToStorage(_ preferences: MobileWebPreferences) {
        storedSymbol = preferences.symbol
        storedInterval = preferences.interval
        storedPeriod = preferences.period
        storedMaxBars = preferences.maxBars
        storedDropLive = preferences.dropLive
        storedUseBodyRange = preferences.useBodyRange
        storedVolumeFilterEnabled = preferences.volumeFilterEnabled
        storedVolumeSMAWindow = preferences.volumeSMAWindow
        storedVolumeMultiplier = preferences.volumeMultiplier
        storedGrayFake = preferences.grayFake
        storedHideMarketClosedGaps = preferences.hideMarketClosedGaps
        storedEnableAutoRefresh = preferences.enableAutoRefresh
        storedRefreshSeconds = preferences.refreshSeconds
    }

    private var launchView: some View {
        VStack(spacing: 14) {
            Image(systemName: "network.badge.shield.half.filled")
                .font(.system(size: 42))
                .foregroundStyle(.blue)

            Text("Connect ManeshTrader")
                .font(.title3.weight(.semibold))

            Text("Set a backend URL reachable from this device, then load the web app in place.")
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
                .frame(maxWidth: 460)

            Button("Open Setup") {
                setupDraft = storedWebPreferences.normalized().setupDefaults
                setupBackendURL = storedBackendURL
                showSetupSheet = true
            }
            .buttonStyle(.borderedProminent)

            if let validationMessage = host.validationMessage {
                Text(validationMessage)
                    .font(.footnote)
                    .foregroundStyle(.red)
                    .multilineTextAlignment(.center)
                    .frame(maxWidth: 460)
            }
        }
        .padding(20)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(
            LinearGradient(
                colors: [
                    Color(uiColor: .systemBackground),
                    Color(uiColor: .secondarySystemBackground),
                ],
                startPoint: .top,
                endPoint: .bottom
            )
        )
    }
}

private struct MobileHelpSheetView: View {
    @Environment(\.dismiss) private var dismiss

    private var helpFileURL: URL? {
        let fm = FileManager.default
        let candidates = [
            Bundle.main.url(forResource: "help", withExtension: "html", subdirectory: "Help"),
            Bundle.main.url(forResource: "help", withExtension: "html"),
            Bundle.main.resourceURL?.appendingPathComponent("Help/help.html"),
            Bundle.main.resourceURL?.appendingPathComponent("help.html"),
        ].compactMap { $0 }

        return candidates.first(where: { fm.fileExists(atPath: $0.path) })
    }

    var body: some View {
        NavigationStack {
            Group {
                if let helpFileURL {
                    MobileHelpDocumentWebView(fileURL: helpFileURL)
                } else {
                    VStack(alignment: .leading, spacing: 8) {
                        Text("Help file not found.")
                            .font(.title3.weight(.semibold))
                        Text("Expected bundled file: help.html")
                            .foregroundStyle(.secondary)
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
                    .padding(24)
                }
            }
            .navigationTitle("Help & Quick Start")
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") { dismiss() }
                }
            }
        }
    }
}

private struct MobileHelpDocumentWebView: UIViewRepresentable {
    let fileURL: URL

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView(frame: .zero)
        webView.allowsBackForwardNavigationGestures = true
        webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL.deletingLastPathComponent())
        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        if webView.url != fileURL {
            webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL.deletingLastPathComponent())
        }
    }
}

private struct MobileWebView: UIViewRepresentable {
    let url: URL
    let reloadToken: Int

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView(frame: .zero)
        webView.customUserAgent = "ManeshTraderMobile"
        webView.allowsBackForwardNavigationGestures = true
        webView.navigationDelegate = context.coordinator
        context.coordinator.attach(webView)
        webView.load(URLRequest(url: url))
        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        if context.coordinator.lastReloadToken != reloadToken || webView.url != url {
            context.coordinator.lastReloadToken = reloadToken
            webView.load(URLRequest(url: url))
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(url: url, reloadToken: reloadToken)
    }

    final class Coordinator: NSObject, WKNavigationDelegate {
        private let url: URL
        private weak var webView: WKWebView?
        private var pendingRetry: DispatchWorkItem?
        var lastReloadToken: Int

        init(url: URL, reloadToken: Int) {
            self.url = url
            self.lastReloadToken = reloadToken
        }

        func attach(_ webView: WKWebView) {
            self.webView = webView
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            pendingRetry?.cancel()
            pendingRetry = nil
        }

        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
            scheduleRetry()
        }

        func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
            scheduleRetry()
        }

        private func scheduleRetry() {
            pendingRetry?.cancel()
            let retry = DispatchWorkItem { [weak self] in
                guard let self, let webView = self.webView else { return }
                webView.load(URLRequest(url: self.url))
            }
            pendingRetry = retry
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: retry)
        }
    }
}

@Observable
@MainActor
private final class MobileTraderHost {
    var reloadToken = 0
    var validationMessage: String?
    var webQueryItems: [URLQueryItem] = []
    var backendURLString = ""

    var serverURL: URL? {
        guard var components = URLComponents(string: backendURLString),
              let scheme = components.scheme?.lowercased(),
              ["http", "https"].contains(scheme),
              components.host != nil else {
            return nil
        }

        components.queryItems = webQueryItems.isEmpty ? nil : webQueryItems
        return components.url
    }

    func applyPreferences(_ preferences: MobileWebPreferences, backendURLString: String) {
        self.backendURLString = backendURLString.trimmingCharacters(in: .whitespacesAndNewlines)
        webQueryItems = preferences.normalized().queryItems

        if serverURL == nil {
            validationMessage = "Enter a valid backend URL with http:// or https:// and a host."
        } else {
            validationMessage = nil
        }
    }

    func reloadWebView() {
        guard serverURL != nil else { return }
        reloadToken += 1
    }
}

private struct MobileUserSetupPreferences {
    static let timeframeOptions = ["1m", "2m", "5m", "15m", "30m", "60m", "90m", "1h", "1d", "5d", "1wk", "1mo"]
    static let periodOptions = ["1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "max"]

    static let `default` = MobileUserSetupPreferences(symbol: "AAPL", timeframe: "1d", period: "6mo", maxBars: 500)

    var symbol: String
    var timeframe: String
    var period: String
    var maxBars: Int

    func normalized() -> MobileUserSetupPreferences {
        let normalizedSymbol = symbol.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        let safeSymbol = normalizedSymbol.isEmpty ? "AAPL" : normalizedSymbol

        let safeTimeframe = Self.timeframeOptions.contains(timeframe) ? timeframe : "1d"
        let safePeriod = Self.periodOptions.contains(period) ? period : "6mo"
        let safeMaxBars = min(5000, max(20, maxBars))

        return MobileUserSetupPreferences(
            symbol: safeSymbol,
            timeframe: safeTimeframe,
            period: safePeriod,
            maxBars: safeMaxBars
        )
    }
}

private struct MobileWebPreferences: Codable {
    var symbol: String
    var interval: String
    var period: String
    var maxBars: Int
    var dropLive: Bool
    var useBodyRange: Bool
    var volumeFilterEnabled: Bool
    var volumeSMAWindow: Int
    var volumeMultiplier: Double
    var grayFake: Bool
    var hideMarketClosedGaps: Bool
    var enableAutoRefresh: Bool
    var refreshSeconds: Int

    init(
        symbol: String,
        interval: String,
        period: String,
        maxBars: Int,
        dropLive: Bool,
        useBodyRange: Bool,
        volumeFilterEnabled: Bool,
        volumeSMAWindow: Int,
        volumeMultiplier: Double,
        grayFake: Bool,
        hideMarketClosedGaps: Bool,
        enableAutoRefresh: Bool,
        refreshSeconds: Int
    ) {
        self.symbol = symbol
        self.interval = interval
        self.period = period
        self.maxBars = maxBars
        self.dropLive = dropLive
        self.useBodyRange = useBodyRange
        self.volumeFilterEnabled = volumeFilterEnabled
        self.volumeSMAWindow = volumeSMAWindow
        self.volumeMultiplier = volumeMultiplier
        self.grayFake = grayFake
        self.hideMarketClosedGaps = hideMarketClosedGaps
        self.enableAutoRefresh = enableAutoRefresh
        self.refreshSeconds = refreshSeconds
    }

    static let `default` = MobileWebPreferences(
        symbol: "AAPL",
        interval: "1d",
        period: "6mo",
        maxBars: 500,
        dropLive: true,
        useBodyRange: false,
        volumeFilterEnabled: false,
        volumeSMAWindow: 20,
        volumeMultiplier: 1.0,
        grayFake: true,
        hideMarketClosedGaps: true,
        enableAutoRefresh: false,
        refreshSeconds: 60
    )

    private enum CodingKeys: String, CodingKey {
        case symbol
        case interval
        case period
        case maxBars = "max_bars"
        case dropLive = "drop_live"
        case useBodyRange = "use_body_range"
        case volumeFilterEnabled = "volume_filter_enabled"
        case volumeSMAWindow = "volume_sma_window"
        case volumeMultiplier = "volume_multiplier"
        case grayFake = "gray_fake"
        case hideMarketClosedGaps = "hide_market_closed_gaps"
        case enableAutoRefresh = "enable_auto_refresh"
        case refreshSeconds = "refresh_sec"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let defaults = Self.default

        symbol = try container.decodeIfPresent(String.self, forKey: .symbol) ?? defaults.symbol
        interval = try container.decodeIfPresent(String.self, forKey: .interval) ?? defaults.interval
        period = try container.decodeIfPresent(String.self, forKey: .period) ?? defaults.period
        maxBars = try container.decodeIfPresent(Int.self, forKey: .maxBars) ?? defaults.maxBars
        dropLive = try container.decodeIfPresent(Bool.self, forKey: .dropLive) ?? defaults.dropLive
        useBodyRange = try container.decodeIfPresent(Bool.self, forKey: .useBodyRange) ?? defaults.useBodyRange
        volumeFilterEnabled = try container.decodeIfPresent(Bool.self, forKey: .volumeFilterEnabled) ?? defaults.volumeFilterEnabled
        volumeSMAWindow = try container.decodeIfPresent(Int.self, forKey: .volumeSMAWindow) ?? defaults.volumeSMAWindow
        volumeMultiplier = try container.decodeIfPresent(Double.self, forKey: .volumeMultiplier) ?? defaults.volumeMultiplier
        grayFake = try container.decodeIfPresent(Bool.self, forKey: .grayFake) ?? defaults.grayFake
        hideMarketClosedGaps = try container.decodeIfPresent(Bool.self, forKey: .hideMarketClosedGaps) ?? defaults.hideMarketClosedGaps
        enableAutoRefresh = try container.decodeIfPresent(Bool.self, forKey: .enableAutoRefresh) ?? defaults.enableAutoRefresh
        refreshSeconds = try container.decodeIfPresent(Int.self, forKey: .refreshSeconds) ?? defaults.refreshSeconds
    }

    func normalized() -> MobileWebPreferences {
        let safeSymbol = {
            let candidate = symbol.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
            return candidate.isEmpty ? "AAPL" : candidate
        }()

        let safeInterval = MobileUserSetupPreferences.timeframeOptions.contains(interval) ? interval : "1d"
        let safePeriod = MobileUserSetupPreferences.periodOptions.contains(period) ? period : "6mo"
        let safeMaxBars = min(5000, max(20, maxBars))
        let safeVolumeSMAWindow = min(100, max(2, volumeSMAWindow))
        let clampedMultiplier = min(3.0, max(0.1, volumeMultiplier))
        let safeVolumeMultiplier = (clampedMultiplier * 10).rounded() / 10
        let safeRefreshSeconds = min(600, max(10, refreshSeconds))

        return MobileWebPreferences(
            symbol: safeSymbol,
            interval: safeInterval,
            period: safePeriod,
            maxBars: safeMaxBars,
            dropLive: dropLive,
            useBodyRange: useBodyRange,
            volumeFilterEnabled: volumeFilterEnabled,
            volumeSMAWindow: safeVolumeSMAWindow,
            volumeMultiplier: safeVolumeMultiplier,
            grayFake: grayFake,
            hideMarketClosedGaps: hideMarketClosedGaps,
            enableAutoRefresh: enableAutoRefresh,
            refreshSeconds: safeRefreshSeconds
        )
    }

    var setupDefaults: MobileUserSetupPreferences {
        MobileUserSetupPreferences(
            symbol: symbol,
            timeframe: interval,
            period: period,
            maxBars: maxBars
        ).normalized()
    }

    func applyingSetup(_ setup: MobileUserSetupPreferences) -> MobileWebPreferences {
        let normalizedSetup = setup.normalized()
        return MobileWebPreferences(
            symbol: normalizedSetup.symbol,
            interval: normalizedSetup.timeframe,
            period: normalizedSetup.period,
            maxBars: normalizedSetup.maxBars,
            dropLive: dropLive,
            useBodyRange: useBodyRange,
            volumeFilterEnabled: volumeFilterEnabled,
            volumeSMAWindow: volumeSMAWindow,
            volumeMultiplier: volumeMultiplier,
            grayFake: grayFake,
            hideMarketClosedGaps: hideMarketClosedGaps,
            enableAutoRefresh: enableAutoRefresh,
            refreshSeconds: refreshSeconds
        )
    }

    var queryItems: [URLQueryItem] {
        [
            URLQueryItem(name: "symbol", value: symbol),
            URLQueryItem(name: "interval", value: interval),
            URLQueryItem(name: "period", value: period),
            URLQueryItem(name: "max_bars", value: String(maxBars)),
            URLQueryItem(name: "drop_live", value: String(dropLive)),
            URLQueryItem(name: "use_body_range", value: String(useBodyRange)),
            URLQueryItem(name: "volume_filter_enabled", value: String(volumeFilterEnabled)),
            URLQueryItem(name: "volume_sma_window", value: String(volumeSMAWindow)),
            URLQueryItem(name: "volume_multiplier", value: String(volumeMultiplier)),
            URLQueryItem(name: "gray_fake", value: String(grayFake)),
            URLQueryItem(name: "hide_market_closed_gaps", value: String(hideMarketClosedGaps)),
            URLQueryItem(name: "enable_auto_refresh", value: String(enableAutoRefresh)),
            URLQueryItem(name: "refresh_sec", value: String(refreshSeconds)),
        ]
    }
}

#Preview {
    MobileContentView()
}
