//
//  ContentView.swift
//  LocalDevVPN
//
//  Created by Stossy11 on 28/03/2025.
//

import Foundation
import NetworkExtension
import SwiftUI

import NavigationBackport

extension Bundle {
    var shortVersion: String { object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0.0.0" }
    var tunnelBundleID: String { bundleIdentifier!.appending(".TunnelProv") }
}

// MARK: - Logging Utility

class VPNLogger: ObservableObject {
    @Published var logs: [String] = []

    static var shared = VPNLogger()

    private init() {}

    func log(_ message: Any, file: String = #file, function: String = #function, line: Int = #line) {
        #if DEBUG
            let fileName = (file as NSString).lastPathComponent
            print("[\(fileName):\(line)] \(function): \(message)")
        #endif

        logs.append("\(message)")
    }
}

// MARK: - Tunnel Manager

class TunnelManager: ObservableObject {
    @Published var hasLocalDeviceSupport = false
    @Published var tunnelStatus: TunnelStatus = .disconnected

    static var shared = TunnelManager()

    @Published var waitingOnSettings: Bool = false
    @Published var vpnManager: NETunnelProviderManager?
    private var vpnObserver: NSObjectProtocol?
    private var isProcessingStatusChange = false
    private let isSimulator: Bool = {
        #if targetEnvironment(simulator)
            return true
        #else
            return false
        #endif
    }()

    private var tunnelDeviceIp: String {
        UserDefaults.standard.string(forKey: "TunnelDeviceIP") ?? "10.7.0.0"
    }

    private var tunnelFakeIp: String {
        UserDefaults.standard.string(forKey: "TunnelFakeIP") ?? "10.7.0.1"
    }

    private var tunnelSubnetMask: String {
        UserDefaults.standard.string(forKey: "TunnelSubnetMask") ?? "255.255.255.0"
    }

    private var tunnelBundleId: String {
        Bundle.main.bundleIdentifier!.appending(".TunnelProv")
    }

    enum TunnelStatus {
        case disconnected
        case connecting
        case connected
        case disconnecting
        case error

        var color: Color {
            switch self {
            case .disconnected: return .gray
            case .connecting: return .orange
            case .connected: return .green
            case .disconnecting: return .orange
            case .error: return .red
            }
        }

        var systemImage: String {
            switch self {
            case .disconnected: return "network.slash"
            case .connecting: return "network.badge.shield.half.filled"
            case .connected: return "checkmark.shield.fill"
            case .disconnecting: return "network.badge.shield.half.filled"
            case .error: return "exclamationmark.shield.fill"
            }
        }

        var localizedTitle: LocalizedStringKey {
            switch self {
            case .disconnected:
                return "disconnected"
            case .connecting:
                return "connecting"
            case .connected:
                return "connected"
            case .disconnecting:
                return "disconnecting"
            case .error:
                return "error"
            }
        }
    }

    private init() {
        if isSimulator {
        loadTunnelPreferences()
            VPNLogger.shared.log("Running on Simulator – VPN calls are mocked")
            DispatchQueue.main.async { [weak self] in
                self?.waitingOnSettings = true
            }
        } else {
            setupStatusObserver()
            loadTunnelPreferences()
        }
    }

    // MARK: - Private Methods

    private func loadTunnelPreferences() {
        NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
            guard let self = self else { return }

            DispatchQueue.main.async {
                if let error = error {
                    VPNLogger.shared.log("Error loading preferences: \(error.localizedDescription)")
                    self.tunnelStatus = .error
                    self.waitingOnSettings = true
                    return
                }

                self.hasLocalDeviceSupport = true
                self.waitingOnSettings = true

                if let managers = managers, !managers.isEmpty {
                    let stosManagers = managers.filter { manager in
                        guard let proto = manager.protocolConfiguration as? NETunnelProviderProtocol else {
                            return false
                        }
                        return proto.providerBundleIdentifier == self.tunnelBundleId
                    }

                    if !stosManagers.isEmpty {
                        if stosManagers.count > 1 {
                            self.cleanupDuplicateManagers(stosManagers)
                        } else if let manager = stosManagers.first {
                            self.vpnManager = manager
                            let currentStatus = manager.connection.status
                            VPNLogger.shared.log("Loaded existing LocalDevVPN tunnel configuration with status: \(currentStatus.rawValue)")
                            self.updateTunnelStatus(from: currentStatus)
                        }
                    } else {
                        VPNLogger.shared.log("No LocalDevVPN tunnel configuration found")
                    }
                } else {
                    VPNLogger.shared.log("No existing tunnel configurations found")
                }
            }
        }
    }

    private func cleanupDuplicateManagers(_ managers: [NETunnelProviderManager]) {
        VPNLogger.shared.log("Found \(managers.count) LocalDevVPN configurations. Cleaning up duplicates...")

        let activeManager = managers.first {
            $0.connection.status == .connected || $0.connection.status == .connecting
        }

        let managerToKeep = activeManager ?? managers.first!

        DispatchQueue.main.async { [weak self] in
            self?.vpnManager = managerToKeep
            self?.updateTunnelStatus(from: managerToKeep.connection.status)
        }

        for manager in managers where manager != managerToKeep {
            manager.removeFromPreferences { error in
                if let error = error {
                    VPNLogger.shared.log("Error removing duplicate VPN: \(error.localizedDescription)")
                } else {
                    VPNLogger.shared.log("Successfully removed duplicate VPN configuration")
                }
            }
        }
    }

    private func setupStatusObserver() {
        vpnObserver = NotificationCenter.default.addObserver(
            forName: .NEVPNStatusDidChange,
            object: nil,
            queue: .main
        ) { [weak self] notification in
            guard let self = self else { return }
            guard let connection = notification.object as? NEVPNConnection else { return }

            VPNLogger.shared.log("VPN Status notification received: \(connection.status.rawValue)")

            // Update status immediately if it's our manager
            if let manager = self.vpnManager, connection == manager.connection {
                self.updateTunnelStatus(from: connection.status)
            }

            self.handleVPNStatusChange(notification: notification)
        }
    }

    private func updateTunnelStatus(from connectionStatus: NEVPNStatus) {
        let newStatus: TunnelStatus
        switch connectionStatus {
        case .invalid, .disconnected:
            newStatus = .disconnected
        case .connecting:
            newStatus = .connecting
        case .connected:
            newStatus = .connected
        case .disconnecting:
            newStatus = .disconnecting
        case .reasserting:
            newStatus = .connecting
        @unknown default:
            newStatus = .error
        }

        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if self.tunnelStatus != newStatus {
                VPNLogger.shared.log("LocalDevVPN status updated from \(self.tunnelStatus) to \(newStatus)")
            }
            self.tunnelStatus = newStatus
        }
    }

    private func createLocalDevVPNConfiguration(completion: @escaping (NETunnelProviderManager?) -> Void) {
        NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
            guard let self = self else {
                completion(nil)
                return
            }

            if let error = error {
                VPNLogger.shared.log("Error checking existing VPN configurations: \(error.localizedDescription)")
                completion(nil)
                return
            }

            if let managers = managers {
                let stosManagers = managers.filter { manager in
                    guard let proto = manager.protocolConfiguration as? NETunnelProviderProtocol else {
                        return false
                    }
                    return proto.providerBundleIdentifier == self.tunnelBundleId
                }

                if let existingManager = stosManagers.first {
                    VPNLogger.shared.log("Found existing LocalDevVPN configuration, using it instead of creating new one")
                    completion(existingManager)
                    return
                }
            }

            let manager = NETunnelProviderManager()
            manager.localizedDescription = "LocalDevVPN"

            let proto = NETunnelProviderProtocol()
            proto.providerBundleIdentifier = self.tunnelBundleId
            proto.serverAddress = "LocalDevVPN's Local Network Tunnel"
            manager.protocolConfiguration = proto

            let onDemandRule = NEOnDemandRuleEvaluateConnection()
            onDemandRule.interfaceTypeMatch = .any
            onDemandRule.connectionRules = [NEEvaluateConnectionRule(
                matchDomains: ["10.7.0.0", "10.7.0.1"],
                andAction: .connectIfNeeded
            )]

            manager.onDemandRules = [onDemandRule]
            manager.isOnDemandEnabled = true
            manager.isEnabled = true

            manager.saveToPreferences { error in
                DispatchQueue.main.async {
                    if let error = error {
                        VPNLogger.shared.log("Error creating LocalDevVPN configuration: \(error.localizedDescription)")
                        completion(nil)
                        return
                    }

                    VPNLogger.shared.log("LocalDevVPN configuration created successfully")
                    completion(manager)
                }
            }
        }
    }

    private func getActiveVPNManager(completion: @escaping (NETunnelProviderManager?) -> Void) {
        NETunnelProviderManager.loadAllFromPreferences { managers, error in
            if let error = error {
                VPNLogger.shared.log("Error loading VPN configurations: \(error.localizedDescription)")
                completion(nil)
                return
            }

            guard let managers = managers else {
                completion(nil)
                return
            }

            let activeManager = managers.first { manager in
                manager.connection.status == .connected || manager.connection.status == .connecting
            }

            completion(activeManager)
        }
    }

    // MARK: - Public Methods

    func toggleVPNConnection() {
        if tunnelStatus == .connected || tunnelStatus == .connecting {
            stopVPN()
        } else {
            startVPN()
        }
    }

    func startVPN() {
        if isSimulator {
            simulateStartVPN()
            return
        }

        if let manager = vpnManager {
            let currentStatus = manager.connection.status
            VPNLogger.shared.log("Current manager status: \(currentStatus.rawValue)")

            if currentStatus == .connected {
                VPNLogger.shared.log("VPN already connected, updating UI")
                DispatchQueue.main.async { [weak self] in
                    self?.tunnelStatus = .connected
                }
                return
            }

            if currentStatus == .connecting {
                VPNLogger.shared.log("VPN already connecting, updating UI")
                DispatchQueue.main.async { [weak self] in
                    self?.tunnelStatus = .connecting
                }
                return
            }
        }

        getActiveVPNManager { [weak self] activeManager in
            guard let self = self else { return }

            if let activeManager = activeManager,
               (activeManager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier != self.tunnelBundleId
            {
                VPNLogger.shared.log("Disconnecting existing VPN connection before starting LocalDevVPN")

                UserDefaults.standard.set(true, forKey: "ShouldStartLocalDevVPNAfterDisconnect")
                activeManager.connection.stopVPNTunnel()
                return
            }

            self.initializeAndStartLocalDevVPN()
        }
    }

    private func initializeAndStartLocalDevVPN() {
        if let manager = vpnManager {
            manager.loadFromPreferences { [weak self] error in
                guard let self = self else { return }

                if let error = error {
                    VPNLogger.shared.log("Error reloading manager: \(error.localizedDescription)")
                    self.createAndStartVPN()
                    return
                }

                self.startExistingVPN(manager: manager)
            }
        } else {
            createAndStartVPN()
        }
    }

    private func createAndStartVPN() {
        NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
            guard let self = self else { return }

            if let error = error {
                VPNLogger.shared.log("Error reloading VPN configurations: \(error.localizedDescription)")
            }

            if let managers = managers {
                let stosManagers = managers.filter { manager in
                    guard let proto = manager.protocolConfiguration as? NETunnelProviderProtocol else {
                        return false
                    }
                    return proto.providerBundleIdentifier == self.tunnelBundleId
                }

                if !stosManagers.isEmpty {
                    DispatchQueue.main.async { [weak self] in
                        self?.vpnManager = stosManagers.first
                    }

                    if stosManagers.count > 1 {
                        self.cleanupDuplicateManagers(stosManagers)
                    }

                    if let manager = stosManagers.first {
                        self.startExistingVPN(manager: manager)
                    }
                    return
                }
            }

            self.createLocalDevVPNConfiguration { [weak self] manager in
                guard let self = self, let manager = manager else { return }
                DispatchQueue.main.async { [weak self] in
                    self?.vpnManager = manager
                }
                self.startExistingVPN(manager: manager)
            }
        }
    }

    private func startExistingVPN(manager: NETunnelProviderManager) {
        // First check the actual current status
        let currentStatus = manager.connection.status
        VPNLogger.shared.log("Current VPN status before start attempt: \(currentStatus.rawValue)")

        if currentStatus == .connected {
            VPNLogger.shared.log("LocalDevVPN tunnel is already connected")
            DispatchQueue.main.async { [weak self] in
                self?.tunnelStatus = .connected
            }
            return
        }

        if currentStatus == .connecting {
            VPNLogger.shared.log("LocalDevVPN tunnel is already connecting")
            DispatchQueue.main.async { [weak self] in
                self?.tunnelStatus = .connecting
            }
            return
        }

        manager.isEnabled = true
        manager.saveToPreferences { [weak self] error in
            guard let self = self else { return }

            if let error = error {
                VPNLogger.shared.log("Error saving preferences: \(error.localizedDescription)")
                DispatchQueue.main.async { [weak self] in
                    self?.tunnelStatus = .error
                }
                return
            }

            manager.loadFromPreferences { [weak self] error in
                guard let self = self else { return }

                if let error = error {
                    VPNLogger.shared.log("Error reloading preferences: \(error.localizedDescription)")
                    DispatchQueue.main.async { [weak self] in
                        self?.tunnelStatus = .error
                    }
                    return
                }

                // Check status again after reload
                let statusAfterReload = manager.connection.status
                VPNLogger.shared.log("VPN status after reload: \(statusAfterReload.rawValue)")

                if statusAfterReload == .connected {
                    VPNLogger.shared.log("VPN is already connected after reload")
                    DispatchQueue.main.async { [weak self] in
                        self?.tunnelStatus = .connected
                    }
                    return
                }

                DispatchQueue.main.async { [weak self] in
                    self?.tunnelStatus = .connecting
                }

                let options: [String: NSObject] = [
                    "TunnelDeviceIP": self.tunnelDeviceIp as NSObject,
                    "TunnelFakeIP": self.tunnelFakeIp as NSObject,
                    "TunnelSubnetMask": self.tunnelSubnetMask as NSObject,
                ]

                do {
                    try manager.connection.startVPNTunnel(options: options)
                    VPNLogger.shared.log("LocalDevVPN tunnel start initiated")
                } catch {
                    DispatchQueue.main.async { [weak self] in
                        self?.tunnelStatus = .error
                    }
                    VPNLogger.shared.log("Failed to start LocalDevVPN tunnel: \(error.localizedDescription)")
                }
            }
        }
    }

    func stopVPN() {
        if isSimulator {
            simulateStopVPN()
            return
        }

        guard let manager = vpnManager else {
            VPNLogger.shared.log("No VPN manager available to stop")
            return
        }

        DispatchQueue.main.async { [weak self] in
            self?.tunnelStatus = .disconnecting
        }

        manager.connection.stopVPNTunnel()
        VPNLogger.shared.log("LocalDevVPN tunnel stop initiated")

        UserDefaults.standard.removeObject(forKey: "ShouldStartLocalDevVPNAfterDisconnect")
    }

    func handleVPNStatusChange(notification: Notification) {
        guard let connection = notification.object as? NEVPNConnection else { return }

        VPNLogger.shared.log("Handling VPN status change: \(connection.status.rawValue)")

        // Always update status if it's our manager's connection
        if let manager = vpnManager, connection == manager.connection {
            VPNLogger.shared.log("Status change is for our LocalDevVPN manager")
            updateTunnelStatus(from: connection.status)
        }

        if connection.status == .disconnected &&
            UserDefaults.standard.bool(forKey: "ShouldStartLocalDevVPNAfterDisconnect")
        {
            UserDefaults.standard.removeObject(forKey: "ShouldStartLocalDevVPNAfterDisconnect")

            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
                self?.initializeAndStartLocalDevVPN()
            }
            return
        }

        // Prevent recursive calls when checking for duplicates
        guard !isProcessingStatusChange else { return }
        isProcessingStatusChange = true

        // Check for duplicates asynchronously without blocking
        DispatchQueue.global(qos: .utility).async { [weak self] in
            guard let self = self else { return }

            NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, _ in
                guard let self = self, let managers = managers, !managers.isEmpty else {
                    DispatchQueue.main.async { [weak self] in
                        self?.isProcessingStatusChange = false
                    }
                    return
                }

                let stosManagers = managers.filter { manager in
                    guard let proto = manager.protocolConfiguration as? NETunnelProviderProtocol else {
                        return false
                    }
                    return proto.providerBundleIdentifier == self.tunnelBundleId
                }

                if stosManagers.count > 1 {
                    DispatchQueue.main.async { [weak self] in
                        self?.cleanupDuplicateManagers(stosManagers)
                    }
                }

                DispatchQueue.main.async { [weak self] in
                    self?.isProcessingStatusChange = false
                }
            }
        }
    }

    // MARK: - Cleanup Utilities

    func cleanupAllVPNConfigurations() {
        if isSimulator {
            VPNLogger.shared.log("Simulator cleanup skipped – no real VPN configurations to remove")
            return
        }

        NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
            guard let self = self else { return }

            if let error = error {
                VPNLogger.shared.log("Error loading VPN configurations for cleanup: \(error.localizedDescription)")
                return
            }

            guard let managers = managers else { return }

            for manager in managers {
                guard let proto = manager.protocolConfiguration as? NETunnelProviderProtocol,
                      proto.providerBundleIdentifier == self.tunnelBundleId
                else {
                    continue
                }

                if manager.connection.status == .connected || manager.connection.status == .connecting {
                    manager.connection.stopVPNTunnel()
                }

                manager.removeFromPreferences { error in
                    if let error = error {
                        VPNLogger.shared.log("Error removing VPN configuration: \(error.localizedDescription)")
                    } else {
                        VPNLogger.shared.log("Successfully removed VPN configuration")
                    }
                }
            }

            DispatchQueue.main.async { [weak self] in
                self?.vpnManager = nil
                self?.tunnelStatus = .disconnected
            }
        }
    }

    deinit {
        if let observer = vpnObserver {
            NotificationCenter.default.removeObserver(observer)
        }
    }

    private func simulateStartVPN() {
        VPNLogger.shared.log("Simulator: pretend to start VPN")
        DispatchQueue.main.async { [weak self] in
            self?.tunnelStatus = .connecting
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak self] in
            self?.tunnelStatus = .connected
            VPNLogger.shared.log("Simulator: VPN marked connected")
        }
    }

    private func simulateStopVPN() {
        VPNLogger.shared.log("Simulator: pretend to stop VPN")
        DispatchQueue.main.async { [weak self] in
            self?.tunnelStatus = .disconnecting
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { [weak self] in
            self?.tunnelStatus = .disconnected
            VPNLogger.shared.log("Simulator: VPN marked disconnected")
        }
    }
}

// MARK: - Views

struct ContentView: View {
    @StateObject private var tunnelManager = TunnelManager.shared
    @State private var showSettings = false
    @State var tunnel = false
    @AppStorage("autoConnect") private var autoConnect = false
    @AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        NBNavigationStack {
            ScrollView {
                VStack(spacing: 16) {
                    TitleWithSettingsRow(showSettings: $showSettings)

                    StatusOverviewCard()

                    ConnectivityControlsCard(
                        action: {
                            tunnelManager.tunnelStatus == .connected ? tunnelManager.stopVPN() : tunnelManager.startVPN()
                        }
                    )

                    if tunnelManager.tunnelStatus == .connected {
                        ConnectionStatsView()
                    }
                }
                .padding(.horizontal)
                .padding(.vertical, 12)
                .frame(maxWidth: .infinity, alignment: .top)
            }
            .applyAdaptiveBounce()
            .background(backgroundColor.ignoresSafeArea())
            .navigationTitle("")
            #if os(iOS)
                .navigationBarTitleDisplayMode(.inline)
            #endif
            .tvOSNavigationBarTitleDisplayMode(.inline)
            .onChange(of: tunnelManager.waitingOnSettings) { finished in
                if tunnelManager.tunnelStatus != .connected && autoConnect && finished {
                    tunnelManager.startVPN()
                }
            }
            .sheet(isPresented: $showSettings) {
                SettingsView()
            }
            .sheet(isPresented: $hasNotCompletedSetup) {
                SetupView()
            }
        }
    }

    private var backgroundColor: Color {
        if colorScheme == .dark {
            return Color(.systemBackground)
        } else {
            return Color(.systemGroupedBackground)
        }
    }
}

struct TitleWithSettingsRow: View {
    @Binding var showSettings: Bool

    var body: some View {
        HStack(spacing: 10) {
            Text("LocalDevVPN")
                .font(.largeTitle)
                .fontWeight(.bold)
                .accessibilityAddTraits(.isHeader)

            Spacer()

            Button {
                showSettings = true
            } label: {
                Image(systemName: "gear")
                    .font(.title2.weight(.semibold))
                    .foregroundColor(.primary)
            }
            .accessibilityLabel(Text("settings"))
        }
        .padding(.top, 4)
    }
}

extension View {
    @ViewBuilder
    func tvOSNavigationBarTitleDisplayMode(_ displayMode: NavigationBarItem.TitleDisplayMode) -> some View {
        #if os(iOS)
            navigationBarTitleDisplayMode(displayMode)
        #else
            self
        #endif
    }

    @ViewBuilder
    func applyAdaptiveBounce() -> some View {
        if #available(iOS 16.4, tvOS 16.4, *) {
            scrollBounceBehavior(.basedOnSize)
        } else {
            self
        }
    }
}

struct StatusOverviewCard: View {
    @StateObject private var tunnelManager = TunnelManager.shared
    @AppStorage("TunnelDeviceIP") private var deviceIP = "10.7.0.0"

    var body: some View {
        DashboardCard {
            VStack(alignment: .leading, spacing: 18) {
                Text("current_status")
                    .font(.headline)

                HStack(spacing: 18) {
                    StatusGlyphView()

                    Text(tunnelManager.tunnelStatus.localizedTitle)
                        .font(.title3)
                        .fontWeight(.semibold)
                        .multilineTextAlignment(.center)
                        .frame(maxWidth: .infinity, alignment: .center)
                }

                Divider()

                HStack {
                    Label {
                        Text(statusTip)
                    } icon: {
                        Image(systemName: "info.circle")
                    }
                    .font(.caption)
                    .foregroundColor(.secondary)

                    Spacer()

                    HStack(spacing: 4) {
                        Text("connected_at")
                        Text(Date(), style: .time)
                    }
                    .font(.caption)
                    .foregroundColor(.secondary)
                }
            }
        }
    }

    private var statusTip: String {
        switch tunnelManager.tunnelStatus {
        case .connected:
            return String(format: NSLocalizedString("connected_to_ip", comment: ""), deviceIP)
        case .connecting:
            return NSLocalizedString("ios_might_ask_you_to_allow_the_vpn", comment: "")
        case .disconnecting:
            return NSLocalizedString("disconnecting_safely", comment: "")
        case .error:
            return NSLocalizedString("open_settings_to_review_details", comment: "")
        default:
            return NSLocalizedString("tap_connect_to_create_the_tunnel", comment: "")
        }
    }
}

struct StatusGlyphView: View {
    @StateObject private var tunnelManager = TunnelManager.shared
    @State private var ringScale: CGFloat = 1.0

    var body: some View {
        ZStack {
            Circle()
                .stroke(tunnelManager.tunnelStatus.color.opacity(0.25), lineWidth: 6)
                .scaleEffect(ringScale, anchor: .center)
                .animation(.easeInOut(duration: 1.2).repeatForever(autoreverses: true), value: ringScale)

            Circle()
                .fill(tunnelManager.tunnelStatus.color.opacity(0.15))

            Image(systemName: tunnelManager.tunnelStatus.systemImage)
                .font(.title)
                .foregroundColor(tunnelManager.tunnelStatus.color)
        }
        .frame(width: 92, height: 92)
        .onAppear(perform: startPulse)
    }

    private func startPulse() {
        DispatchQueue.main.async {
            ringScale = 1.08
        }
    }
}

struct ConnectivityControlsCard: View {
    let action: () -> Void

    var body: some View {
        DashboardCard {
            VStack(alignment: .leading, spacing: 18) {
                VStack(alignment: .leading, spacing: 4) {
                    Text("connection")
                        .font(.headline)
                    Text("start_or_stop_the_secure_local_tunnel")
                        .font(.footnote)
                        .foregroundColor(.secondary)
                }

                ConnectionButton(action: action)
            }
        }
    }
}

struct ConnectionInfoRow: View {
    let title: LocalizedStringKey
    let value: String
    let icon: String

    var body: some View {
        HStack(spacing: 12) {
            Image(systemName: icon)
                .font(.body)
                .foregroundColor(.accentColor)
                .frame(width: 24)
            VStack(alignment: .leading, spacing: 2) {
                Text(title)
                    .font(.caption)
                    .foregroundColor(.secondary)
                Text(value)
                    .font(.body)
                    .foregroundColor(.primary)
            }
            Spacer()
        }
    }
}

struct ConnectionButton: View {
    @StateObject private var tunnelManager = TunnelManager.shared
    let action: () -> Void
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        Button(action: action) {
            HStack {
                Text(buttonText)
                    .font(.headline)
                    .fontWeight(.semibold)

                if tunnelManager.tunnelStatus == .connecting || tunnelManager.tunnelStatus == .disconnecting {
                    ProgressView()
                        .progressViewStyle(CircularProgressViewStyle())
                        .padding(.leading, 5)
                }
            }
            .frame(maxWidth: .infinity)
            .frame(height: 56)
            .background(buttonBackground)
            .foregroundColor(.white)
            .clipShape(Capsule())
            .shadow(color: shadowColor, radius: 10, x: 0, y: 5)
        }
        .disabled(tunnelManager.tunnelStatus == .connecting || tunnelManager.tunnelStatus == .disconnecting)
    }

    private var buttonText: String {
        switch tunnelManager.tunnelStatus {
        case .connected:
            return NSLocalizedString("disconnect", comment: "")
        case .connecting:
            return NSLocalizedString("connecting_ellipsis", comment: "")
        case .disconnecting:
            return NSLocalizedString("disconnecting_ellipsis", comment: "")
        default:
            return NSLocalizedString("connect", comment: "")
        }
    }

    private var buttonBackground: some View {
        Group {
            if tunnelManager.tunnelStatus == .connected {
                LinearGradient(
                    gradient: Gradient(colors: [Color.red.opacity(0.8), Color.red]),
                    startPoint: .leading,
                    endPoint: .trailing
                )
            } else {
                LinearGradient(
                    gradient: Gradient(colors: [Color.blue.opacity(0.8), Color.blue]),
                    startPoint: .leading,
                    endPoint: .trailing
                )
            }
        }
    }

    private var shadowColor: Color {
        colorScheme == .dark ? Color.black.opacity(0.5) : Color.black.opacity(0.15)
    }
}

struct ConnectionStatsView: View {
    @StateObject private var tunnelManager = TunnelManager.shared
    @AppStorage("TunnelDeviceIP") private var deviceIP = "10.7.0.0"
    @AppStorage("TunnelFakeIP") private var fakeIP = "10.7.0.1"
    @AppStorage("TunnelSubnetMask") private var subnetMask = "255.255.255.0"

    var body: some View {
        DashboardCard {
            VStack(alignment: .leading, spacing: 12) {
                VStack(alignment: .leading, spacing: 3) {
                    Text("session_details")
                        .font(.headline)
                    Text("live_stats_while_the_tunnel_is_connected")
                        .font(.footnote)
                        .foregroundColor(.secondary)
                }

                Divider()

                Text("network_configuration")
                    .font(.caption)
                    .foregroundColor(.secondary)

                ConnectionInfoRow(
                    title: "local_device_ip",
                    value: deviceIP,
                    icon: "desktopcomputer"
                )

                ConnectionInfoRow(
                    title: "tunnel_ip",
                    value: fakeIP,
                    icon: "point.3.filled.connected.trianglepath.dotted"
                )

                ConnectionInfoRow(
                    title: "subnet_mask",
                    value: subnetMask,
                    icon: "network"
                )
            }
        }
    }

}

struct StatItemView: View {
    let title: LocalizedStringKey
    let value: String
    let icon: String

    var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            HStack(spacing: 6) {
                Image(systemName: icon)
                    .foregroundColor(.accentColor)
                    .font(.caption)
                Text(title)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            Text(value)
                .font(.headline)
                .foregroundColor(.primary)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }
}

struct DashboardCard<Content: View>: View {
    private let content: () -> Content
    @Environment(\.colorScheme) private var colorScheme

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        content()
            .padding()
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(
                RoundedRectangle(cornerRadius: 22, style: .continuous)
                    .fill(Color(.secondarySystemBackground))
            )
            .overlay(
                RoundedRectangle(cornerRadius: 22, style: .continuous)
                    .stroke(borderColor)
            )
            .shadow(color: shadowColor, radius: 12, x: 0, y: 6)
    }

    private var borderColor: Color {
        colorScheme == .dark ? Color.white.opacity(0.08) : Color.black.opacity(0.06)
    }

    private var shadowColor: Color {
        colorScheme == .dark ? Color.black.opacity(0.5) : Color.black.opacity(0.12)
    }
}

// MARK: - Updated SettingsView

struct SettingsView: View {
    @Environment(\.presentationMode) var presentationMode
    @AppStorage("selectedLanguage") private var selectedLanguage = Locale.current.languageCode ?? "en"
    @AppStorage("TunnelDeviceIP") private var deviceIP = "10.7.0.0"
    @AppStorage("TunnelFakeIP") private var fakeIP = "10.7.0.1"
    @AppStorage("TunnelSubnetMask") private var subnetMask = "255.255.255.0"
    @AppStorage("autoConnect") private var autoConnect = false
    @AppStorage("shownTunnelAlert") private var shownTunnelAlert = false
    @StateObject private var tunnelManager = TunnelManager.shared
    @AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true

    @State private var showNetworkWarning = false
    @State private var showRestartPopUp = false

    var body: some View {
        NBNavigationStack {
            List {
                Section(header: Text("connection_settings")) {
                    Toggle("auto_connect_on_launch", isOn: $autoConnect)
                    NavigationLink(destination: ConnectionLogView()) {
                        Label("connection_logs", systemImage: "doc.text")
                    }
                }

                Section(header: Text("network_configuration")) {
                    Group {
                        networkConfigRow(label: "tunnel_ip", text: $deviceIP)
                        networkConfigRow(label: "device_ip", text: $fakeIP)
                        networkConfigRow(label: "subnet_mask", text: $subnetMask)
                    }
                }

                Section(header: Text("app_information")) {
                    Button {
                        UIApplication.shared.open(URL(string: "https://jkcoxson.com/cdn/LocalDevVPN/LocalDevVPNPrivacyPolicy.md")!, options: [:])
                    } label: {
                        Label("privacy_policy", systemImage: "lock.shield")
                    }
                    NavigationLink(destination: DataCollectionInfoView()) {
                        Label("data_collection_policy", systemImage: "hand.raised.slash")
                    }
                    HStack {
                        Text("app_version")
                        Spacer()
                        Text(Bundle.main.shortVersion)
                            .foregroundColor(.secondary)
                    }
                    NavigationLink(destination: HelpView()) {
                        Text("help_and_support")
                    }
                }

                Section(header: Text("language")) {
                    Picker("dropdown_language", selection: $selectedLanguage) {
                        Text("english").tag("en")
                        Text("spanish").tag("es")
                        Text("italian").tag("it")
                        Text("polish").tag("pl")
                        Text("korean").tag("ko")
                    }
                    .onChange(of: selectedLanguage) { newValue in
                        let languageCode = newValue
                        LanguageManager.shared.updateLanguage(to: languageCode)
                        showRestartPopUp = true
                    }
                    .alert(isPresented: $showRestartPopUp) {
                        Alert(
                            title: Text("restart_title"),
                            message: Text("restart_message"),
                            dismissButton: .cancel(Text("understand_button")) {
                                showRestartPopUp = true
                            }
                        )
                    }
                }
            }
            .alert(isPresented: $showNetworkWarning) {
                Alert(
                    title: Text("warning_alert"),
                    message: Text("warning_message"),
                    dismissButton: .cancel(Text("understand_button")) {
                        shownTunnelAlert = true

                        deviceIP = "10.7.0.0"
                        fakeIP = "10.7.0.1"
                        subnetMask = "255.255.255.0"
                    }
                )
            }
            .navigationTitle(Text("settings"))
            .tvOSNavigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("done") {
                        dismiss()
                    }
                }
            }
        }
    }

    private func dismiss() {
        presentationMode.wrappedValue.dismiss()
    }

    private func networkConfigRow(label: LocalizedStringKey, text: Binding<String>) -> some View {
        HStack {
            Text(label)
            Spacer()
            TextField(label, text: text)
                .multilineTextAlignment(.trailing)
                .foregroundColor(.secondary)
                .keyboardType(.numbersAndPunctuation)
                .onChange(of: text.wrappedValue) { _ in
                    if !shownTunnelAlert {
                        showNetworkWarning = true
                    }

                    tunnelManager.vpnManager?.saveToPreferences { error in
                        if let error = error {
                            VPNLogger.shared.log(error.localizedDescription)
                        }
                    }
                }
        }
    }
}

// MARK: - New Data Collection Info View

struct DataCollectionInfoView: View {
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 20) {
                Text("data_collection_policy_title")
                    .font(.title)
                    .fontWeight(.bold)
                    .padding(.bottom, 10)

                GroupBox(label: Label("no_data_collection", systemImage: "hand.raised.slash").font(.headline)) {
                    Text("no_data_collection_description")
                        .padding(.vertical)
                }

                GroupBox(label: Label("local_processing_only", systemImage: "iphone").font(.headline)) {
                    Text("local_processing_only_description")
                        .padding(.vertical)
                }

                GroupBox(label: Label("no_third_party_sharing", systemImage: "person.2.slash").font(.headline)) {
                    Text("no_third_party_sharing_description")
                        .padding(.vertical)
                }

                GroupBox(label: Label("why_use_network_permissions", systemImage: "network").font(.headline)) {
                    Text("why_use_network_permissions_description")
                        .padding(.vertical)
                }

                GroupBox(label: Label("our_promise", systemImage: "checkmark.seal").font(.headline)) {
                    Text("our_promise_description")
                        .padding(.vertical)
                }
            }
            .padding()
        }
        .navigationTitle(Text("data_collection_policy_nav"))
        .tvOSNavigationBarTitleDisplayMode(.inline)
    }
}

struct ConnectionLogView: View {
    @StateObject var logger = VPNLogger.shared
    var body: some View {
        List(logger.logs, id: \.self) { log in
            Text(log)
                .font(.system(.body, design: .monospaced))
        }
        .navigationTitle(Text("logs_nav"))
        .tvOSNavigationBarTitleDisplayMode(.inline)
    }
}

struct HelpView: View {
    var body: some View {
        List {
            Section(header: Text("faq_header")) {
                NavigationLink("faq_q1") {
                    VStack(alignment: .leading, spacing: 15) {
                        Text("faq_q1_a1")
                            .padding(.bottom, 10)
                        Text("faq_common_use_cases")
                            .fontWeight(.medium)
                        Text("faq_case1")
                        Text("faq_case2")
                        Text("faq_case3")
                        Text("faq_case4")
                    }
                    .padding()
                }
                NavigationLink("faq_q2") {
                    VStack(alignment: .leading, spacing: 15) {
                        Text("faq_q2_a1")
                            .padding(.bottom, 10)
                            .font(.headline)
                        Text("faq_q2_point1")
                        Text("faq_q2_point2")
                        Text("faq_q2_point3")
                        Text("faq_q2_point4")
                        Text("faq_q2_a2")
                            .padding(.top, 10)
                    }
                    .padding()
                }
                NavigationLink("faq_q3") {
                    VStack(alignment: .leading, spacing: 15) {
                        Text("faq_q3_a1")
                            .padding(.bottom, 10)
                        Text("faq_troubleshoot_header")
                            .font(.headline)
                        Text("faq_troubleshoot1")
                        Text("faq_troubleshoot2")
                        Text("faq_troubleshoot3")
                        Text("faq_troubleshoot4")
                    }
                    .padding()
                }
                NavigationLink("faq_q4") {
                    VStack(alignment: .leading, spacing: 15) {
                        Text("faq_q4_intro")
                            .font(.headline)
                            .padding(.bottom, 10)
                        Text("faq_q4_case1")
                        Text("faq_q4_case2")
                        Text("faq_q4_case3")
                        Text("faq_q4_case4")
                        Text("faq_q4_conclusion")
                            .padding(.top, 10)
                    }
                    .padding()
                }
            }
            Section(header: Text("business_model_header")) {
                NavigationLink("biz_q1") {
                    VStack(alignment: .leading, spacing: 15) {
                        Text("biz_q1_a1")
                            .padding(.bottom, 10)
                        Text("biz_key_points_header")
                            .font(.headline)
                        Text("biz_point1")
                        Text("biz_point2")
                        Text("biz_point3")
                        Text("biz_point4")
                        Text("biz_point5")
                    }
                    .padding()
                }
            }
            Section(header: Text("app_info_header")) {
                HStack {
                    Image(systemName: "exclamationmark.shield")
                    Text("requires_ios")
                }
                HStack {
                    Image(systemName: "lock.shield")
                    Text("uses_network_extension")
                }
            }
        }
        .navigationTitle(Text("help_and_support_nav"))
        .tvOSNavigationBarTitleDisplayMode(.inline)
    }
}

struct SetupView: View {
    @Environment(\.presentationMode) var presentationMode
    @AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true
    @State private var currentPage = 0
    let pages = [
        SetupPage(
            title: "setup_welcome_title",
            description: "setup_welcome_description",
            imageName: "checkmark.shield.fill",
            details: "setup_welcome_details"
        ),
        SetupPage(
            title: "setup_why_title",
            description: "setup_why_description",
            imageName: "person.2.fill",
            details: "setup_why_details"
        ),
        SetupPage(
            title: "setup_easy_title",
            description: "setup_easy_description",
            imageName: "hand.tap.fill",
            details: "setup_easy_details"
        ),
        SetupPage(
            title: "setup_privacy_title",
            description: "setup_privacy_description",
            imageName: "lock.shield.fill",
            details: "setup_privacy_details"
        ),
    ]
    var body: some View {
        NBNavigationStack {
            VStack {
                TabView(selection: $currentPage) {
                    ForEach(0 ..< pages.count, id: \.self) { index in
                        SetupPageView(page: pages[index])
                            .tag(index)
                    }
                }
                .tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
                Spacer()
                if currentPage == pages.count - 1 {
                    Button {
                        hasNotCompletedSetup = false
                        dismiss()
                    } label: {
                        Text("setup_get_started")
                            .font(.headline)
                            .fontWeight(.semibold)
                            .frame(height: 50)
                            .frame(maxWidth: .infinity)
                            .background(Color.blue)
                            .foregroundColor(.white)
                            .cornerRadius(10)
                            .padding(.horizontal)
                    }
                    .padding(.bottom)
                } else {
                    Button {
                        withAnimation { currentPage += 1 }
                    } label: {
                        Text("setup_next")
                            .font(.headline)
                            .fontWeight(.semibold)
                            .frame(height: 50)
                            .frame(maxWidth: .infinity)
                            .background(Color.blue)
                            .foregroundColor(.white)
                            .cornerRadius(10)
                            .padding(.horizontal)
                    }
                    .padding(.bottom)
                }
            }
            .navigationTitle(Text("setup_nav"))
            .tvOSNavigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("setup_skip") { hasNotCompletedSetup = false; dismiss() }
                }
            }
        }
    }

    private func dismiss() {
        presentationMode.wrappedValue.dismiss()
    }
}

struct SetupPage {
    let title: LocalizedStringKey
    let description: LocalizedStringKey
    let imageName: String
    let details: LocalizedStringKey
}

struct SetupPageView: View {
    let page: SetupPage

    var body: some View {
        VStack(spacing: tvOSSpacing) {
            Image(systemName: page.imageName)
                .font(.system(size: tvOSImageSize))
                .foregroundColor(.blue)
                .padding(.top, tvOSTopPadding)

            Text(page.title)
                .font(tvOSTitleFont)
                .fontWeight(.bold)
                .multilineTextAlignment(.center)

            Text(page.description)
                .font(tvOSDescriptionFont)
                .foregroundColor(.secondary)
                .multilineTextAlignment(.center)

            ScrollView {
                Text(page.details)
                    .font(tvOSBodyFont)
                    .multilineTextAlignment(.leading)
                    .padding(.horizontal)
            }

            Spacer()
        }
        .padding()
    }

    // MARK: - Conditional sizes for tvOS

    private var tvOSImageSize: CGFloat {
        #if os(tvOS)
            return 60
        #else
            return 80
        #endif
    }

    private var tvOSTopPadding: CGFloat {
        #if os(tvOS)
            return 30
        #else
            return 50
        #endif
    }

    private var tvOSSpacing: CGFloat {
        #if os(tvOS)
            return 20
        #else
            return 30
        #endif
    }

    private var tvOSTitleFont: Font {
        #if os(tvOS)
            return .headline // .system(size: 35).bold()
        #else
            return .title
        #endif
    }

    private var tvOSDescriptionFont: Font {
        #if os(tvOS)
            return .subheadline
        #else
            return .headline
        #endif
    }

    private var tvOSBodyFont: Font {
        #if os(tvOS)
            return .system(size: 18).bold()
        #else
            return .body
        #endif
    }
}

class LanguageManager: ObservableObject {
    static let shared = LanguageManager()
    @Published var currentLanguage: String = Locale.current.languageCode ?? "en"
    private let supportedLanguages = ["en", "es", "it", "pl", "ko"]

    func updateLanguage(to languageCode: String) {
        if supportedLanguages.contains(languageCode) {
            currentLanguage = languageCode
            UserDefaults.standard.set([languageCode], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
        } else {
            currentLanguage = "en" // FALLBACK TO DEFAULT LANGUAGE
            UserDefaults.standard.set(["en"], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
        }
    }
}

#if os(tvOS)
    @ViewBuilder
    func GroupBox<Content: View>(
        label: some View,
        @ViewBuilder content: @escaping () -> Content
    ) -> some View {
        #if os(tvOS)
            tvOSGroupBox(label: {
                label
            }, content: content)
        #else
            SwiftUI.GroupBox(label: label, content: content)
        #endif
    }

    struct tvOSGroupBox<Label: View, Content: View>: View {
        @ViewBuilder let label: () -> Label
        @ViewBuilder let content: () -> Content

        init(
            @ViewBuilder label: @escaping () -> Label,
            @ViewBuilder content: @escaping () -> Content
        ) {
            self.label = label
            self.content = content
        }

        var body: some View {
            VStack(alignment: .leading, spacing: 8) {
                label()
                    .font(.headline)

                content()
                    .padding(.top, 4)
            }
            .padding()
            .background(
                RoundedRectangle(cornerRadius: 12, style: .continuous)
                    .fill(.secondary)
            )
            .overlay(
                RoundedRectangle(cornerRadius: 12, style: .continuous)
                    .stroke(.separator, lineWidth: 0.5)
            )
        }
    }
#endif

#Preview {
    ContentView()
}
