// Copyright 2015-present 650 Industries. All rights reserved.

import SwiftUI
import ExpoModulesCore

// swiftlint:disable:next line_length
private let selectedGesturesInfoMessage = "Selected gestures will toggle the developer menu while inside a preview. The menu allows you to reload or return to home and exposes developer tools."

struct SettingsTabView: View {
  @EnvironmentObject var viewModel: DevLauncherViewModel
  @State private var showCopiedMessage = false
  @State private var defaultPageSize: Int = 10
  @State private var showCacheClearedMessage = false

  private func createBuildInfoJSON() -> String {
    let buildInfoDict: [String: Any] = [
      "runtimeVersion": viewModel.buildInfo["runtimeVersion"] as? String ?? "",
      "sdkVersion": viewModel.structuredBuildInfo.sdkVersion ?? "",
      "appName": viewModel.buildInfo["appName"] as? String ?? "",
      "appVersion": viewModel.buildInfo["appVersion"] as? String ?? ""
    ]

    do {
      let jsonData = try JSONSerialization.data(withJSONObject: buildInfoDict, options: .prettyPrinted)
      return String(data: jsonData, encoding: .utf8) ?? "{}"
    } catch {
      return "{}"
    }
  }

  var body: some View {
    ScrollView {
      VStack(alignment: .leading, spacing: 24) {
        SafeAreaTopPadding(manualInset: viewModel.topSafeAreaInset)
        titleSection
        showMenuAtLaunch
        gestures

        Text(selectedGesturesInfoMessage)
          .font(.system(size: 13))
          .foregroundStyle(.secondary)

        #if !targetEnvironment(simulator)
        localNetworkDebugSettings
        #endif

        VStack(alignment: .leading, spacing: 8) {
          Text("system".uppercased())
            .font(.caption)
            .foregroundColor(.primary.opacity(0.6))
          Divider()
          version
          Divider()
          copyToClipboardButton
        }

        if isAdminUser {
          debugSettings
          easUpdateConfig
        }
      }
      .padding()
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    #if os(tvOS)
    .background()
    #endif
    #if !os(macOS)
    .navigationBarHidden(true)
    #endif
    #if os(iOS) && !targetEnvironment(simulator)
    .task {
      viewModel.refreshPermissionStatus()
    }
    .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
      viewModel.refreshPermissionStatus()
    }
    #endif
  }

  private var showMenuAtLaunch: some View {
    HStack {
      Image("show-menu-at-launch", bundle: getDevLauncherBundle())
        .resizable()
        .frame(width: 24, height: 24)
        .opacity(0.6)
      Toggle("Show menu at launch", isOn: $viewModel.showOnLaunch)
    }
    .padding()
    .background(Color.expoSecondarySystemBackground)
    .cornerRadius(12)
  }

  private var titleSection: some View {
    HStack {
      Spacer()
      VStack {
        Image(systemName: "gearshape")
          .resizable()
          .frame(width: 56, height: 56)
          .opacity(0.3)

        Text("Settings")
          .font(.title2)
          .padding(.horizontal, 20)
      }
      Spacer()
    }
  }

  private var gestures: some View {
    VStack(alignment: .leading) {
      Text("Menu Gestures".uppercased())
        .font(.caption)
        .foregroundColor(.primary.opacity(0.6))

      VStack {
        HStack {
          Image("shake-device", bundle: getDevLauncherBundle())
            .resizable()
            .frame(width: 24, height: 24)
            .opacity(0.6)
          Toggle("Shake device", isOn: $viewModel.shakeDevice)
        }
        .padding()

        Divider()

        HStack {
          Image("three-finger-long-press", bundle: getDevLauncherBundle())
            .resizable()
            .frame(width: 24, height: 24)
            .opacity(0.6)
          Toggle("Three-finger long-press", isOn: $viewModel.threeFingerLongPress)
        }
        .padding()
      }
      .background(Color.expoSecondarySystemBackground)
      .cornerRadius(12)
    }
  }

  private var version: some View {
    HStack {
      Text("Version")
      Spacer()
      Text(viewModel.buildInfo["runtimeVersion"] as? String ?? "")
        .foregroundColor(.secondary)
    }
  }

  private var copyToClipboardButton: some View {
    HStack {
#if os(tvOS)
      Button("Clipboard not available on tvOS") {}
#else
      Button(showCopiedMessage ? "Copied to clipboard!" : "Copy system info") {
        let buildInfoJSON = createBuildInfoJSON()
        let clipboard = UIPasteboard.general
        clipboard.string = buildInfoJSON
        showCopiedMessage = true

        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
          showCopiedMessage = false
        }
      }
      Spacer()
      Image(systemName: "clipboard")
        .resizable()
        .scaledToFit()
        .frame(width: 16, height: 16)
        .foregroundColor(.blue)
#endif
    }
  }

  private var isAdminUser: Bool {
    return viewModel.user?.isExpoAdmin == true
  }

  private var debugSettings: some View {
    Section("Debug Settings") {
      Button(showCacheClearedMessage ? "Network cache cleared!" : "Clear network cache") {
        clearNetworkCache()
      }
      .foregroundColor(showCacheClearedMessage ? .green : nil)

      VStack(alignment: .leading) {
        Text("Default Page Size")
        Text("Sets the number of items fetched for branches and updates")
          .foregroundStyle(.secondary)
          .font(.footnote)
        Picker("", selection: $defaultPageSize) {
          Text("1").tag(1)
          Text("5").tag(5)
          Text("10").tag(10)
        }
        .pickerStyle(.segmented)
      }
    }
  }

  private var easUpdateConfig: some View {
    Section("EAS Update Configuration") {
      VStack(alignment: .leading, spacing: 8) {
        Text(createEASConfigJSON())
          .font(.system(.caption, design: .monospaced))
        #if !os(tvOS)
          .textSelection(.enabled)
        #endif
          .padding(.vertical, 4)
      }
    }
  }

  private func clearNetworkCache() {
    URLCache.shared.removeAllCachedResponses()

    showCacheClearedMessage = true
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
      showCacheClearedMessage = false
    }
  }

  private func createEASConfigJSON() -> String {
    let appId = viewModel.structuredBuildInfo.appId
    let runtimeVersion = viewModel.structuredBuildInfo.runtimeVersion
    let usesEASUpdates = viewModel.structuredBuildInfo.usesEASUpdates
    let projectUrl = viewModel.structuredBuildInfo.projectUrl ?? ""

    return """
    {
      "appId": "\(appId)",
      "runtimeVersion": "\(runtimeVersion)",
      "usesEASUpdates": \(usesEASUpdates),
      "projectUrl": "\(projectUrl)"
    }
    """
  }

  #if !targetEnvironment(simulator)
  private var localNetworkDebugSettings: some View {
    VStack(alignment: .leading, spacing: 8) {
      VStack(spacing: 0) {
        Toggle("Local Network", isOn: .constant(viewModel.permissionStatus == .granted))
          .disabled(true)
          .padding()

        if viewModel.permissionStatus == .denied {
          Divider()

          #if os(iOS)
          Button {
            if let url = URL(string: UIApplication.openSettingsURLString) {
              UIApplication.shared.open(url)
            }
          } label: {
            HStack {
              Text("Open App Settings")
              Spacer()
              Image(systemName: "gear")
                .foregroundColor(.blue)
            }
          }
          .padding()
          #endif
        }
      }
      .background(Color.expoSecondarySystemBackground)
      .cornerRadius(12)
    }
  }
  #endif
}
