import type { SiteConfig } from "@/types/config"
import { AwsClient } from "@/lib/aws4fetch"
import { logger } from "./logger"

type ConfigSource = "browser" | "localStorage" | "server" | "default"

interface VersionConfigResponse {
  version?: string
  date?: string
  versionInfo?: string
}

export interface ConfigResult {
  config: SiteConfig | null
  source: ConfigSource
  error?: string
}

interface HostInfo {
  protocol: string
  host: string
  serverHost: string
}

export interface ServerHealthCheckResult {
  healthy: boolean
  url?: string
  status?: number
  error?: string
}

const STORAGE_KEY = "rustfs-server-host"
const CREDENTIALS_KEY = "auth.credentials"
const PERMANENT_CREDENTIALS_KEY = "auth.permanent"
const DEFAULT_REGION = "us-east-1"
const API_PATH = "/rustfs/admin/v3"
const VERSION_PATH = "/rustfs/console/version"
const REQUEST_TIMEOUT = 5000
const HEALTH_REQUEST_TIMEOUT = 5000
const HEALTH_PATHS = ["/rustfs/console/health", "/health"] as const

const getApiPrefix = (): string => (process.env.NEXT_PUBLIC_API_PREFIX || "").replace(/\/$/, "")

const isBrowser = (): boolean => typeof window !== "undefined"

const getCurrentHostInfo = (): HostInfo | null => {
  if (!isBrowser()) return null

  const protocol = window.location.protocol.replace(":", "")
  const host = window.location.host
  const serverHost = `${protocol}://${host}`

  return { protocol, host, serverHost }
}

export const createDefaultConfig = (serverHost: string): SiteConfig => {
  const apiPrefix = getApiPrefix()
  return {
    serverHost,
    api: {
      baseURL: `${serverHost}${apiPrefix}${API_PATH}`,
    },
    s3: {
      endpoint: serverHost,
      region: DEFAULT_REGION,
      accessKeyId: "",
      secretAccessKey: "",
    },
  }
}

export const getStoredHostConfig = (): ConfigResult => {
  if (!isBrowser()) {
    return { config: null, source: "localStorage", error: "Not in browser environment" }
  }

  const savedHost = localStorage.getItem(STORAGE_KEY)
  if (!savedHost) {
    return { config: null, source: "localStorage", error: "No saved host found" }
  }

  try {
    const url = new URL(savedHost)
    const serverHost = `${url.protocol}//${url.host}`
    const config = createDefaultConfig(serverHost)
    return { config, source: "localStorage" }
  } catch (error) {
    const errorMessage = `Invalid saved host configuration: ${error instanceof Error ? error.message : "Unknown error"}`
    logger.warn(errorMessage)
    return { config: null, source: "localStorage", error: errorMessage }
  }
}

export const getCurrentBrowserConfig = (): ConfigResult => {
  const hostInfo = getCurrentHostInfo()
  if (!hostInfo) {
    return { config: null, source: "browser", error: "Not in browser environment" }
  }

  const config = createDefaultConfig(hostInfo.serverHost)
  return { config, source: "browser" }
}

const parseStoredJson = <T>(value: string | null): T | null => {
  if (!value) return null
  try {
    return JSON.parse(value) as T
  } catch {
    return null
  }
}

const isExpired = (expiration?: string) => {
  if (!expiration) return false
  return new Date(expiration) < new Date()
}

const getStoredSigningCredentials = (): {
  accessKeyId: string
  secretAccessKey: string
  sessionToken?: string
} | null => {
  if (!isBrowser()) return null

  const stored = parseStoredJson<{
    AccessKeyId?: string
    SecretAccessKey?: string
    SessionToken?: string
    Expiration?: string
  }>(localStorage.getItem(CREDENTIALS_KEY))

  if (stored?.AccessKeyId && stored?.SecretAccessKey && stored?.SessionToken && !isExpired(stored.Expiration)) {
    return {
      accessKeyId: stored.AccessKeyId,
      secretAccessKey: stored.SecretAccessKey,
      sessionToken: stored.SessionToken,
    }
  }

  const permanent = parseStoredJson<{
    AccessKeyId?: string
    SecretAccessKey?: string
  }>(localStorage.getItem(PERMANENT_CREDENTIALS_KEY))

  if (permanent?.AccessKeyId && permanent?.SecretAccessKey) {
    return {
      accessKeyId: permanent.AccessKeyId,
      secretAccessKey: permanent.SecretAccessKey,
    }
  }

  return null
}

export const fetchVersionConfigFromServer = async (serverHost: string): Promise<VersionConfigResponse | null> => {
  const configUrl = `${serverHost}${VERSION_PATH}`

  try {
    const credentials = getStoredSigningCredentials()
    if (!credentials) {
      logger.warn("Skip version config fetch: no signing credentials available")
      return null
    }

    const client = new AwsClient({
      accessKeyId: credentials.accessKeyId,
      secretAccessKey: credentials.secretAccessKey,
      sessionToken: credentials.sessionToken,
      service: "s3",
      region: DEFAULT_REGION,
    })

    const response = await client.fetch(configUrl, {
      method: "GET",
      headers: { "Content-Type": "application/json" },
      signal: AbortSignal.timeout(REQUEST_TIMEOUT),
    })

    if (!response.ok) {
      logger.warn(`Failed to fetch version config from ${configUrl}: ${response.status} ${response.statusText}`)
      return null
    }

    const data: VersionConfigResponse = await response.json()

    if (!(typeof data === "object" && data !== null)) {
      logger.warn("Invalid version config: not a valid object")
      return null
    }

    return data
  } catch (error) {
    logger.warn(
      `Error fetching version config from server: ${error instanceof Error ? error.message : "Unknown error"}`,
    )
    return null
  }
}

const requestHealth = async (url: string): Promise<Response> => {
  const headResponse = await fetch(url, {
    method: "HEAD",
    signal: AbortSignal.timeout(HEALTH_REQUEST_TIMEOUT),
  })

  if (headResponse.status !== 405) return headResponse

  return fetch(url, {
    method: "GET",
    signal: AbortSignal.timeout(HEALTH_REQUEST_TIMEOUT),
  })
}

export const checkServerHealth = async (serverHost: string): Promise<ServerHealthCheckResult> => {
  const normalizedHost = serverHost.replace(/\/+$/, "")
  let lastError = "Unknown health check error"

  for (const path of HEALTH_PATHS) {
    const healthUrl = `${normalizedHost}${path}`

    try {
      const response = await requestHealth(healthUrl)
      if (response.ok) {
        return {
          healthy: true,
          url: healthUrl,
          status: response.status,
        }
      }

      lastError = `${response.status} ${response.statusText || "Health check failed"}`
    } catch (error) {
      lastError = error instanceof Error ? error.message : "Health check request failed"
    }
  }

  return {
    healthy: false,
    error: lastError,
  }
}

export const getServerDefaultConfig = (): ConfigResult => {
  const defaultServerHost = "http://localhost:9000"
  const config = createDefaultConfig(defaultServerHost)
  return { config, source: "default" }
}

export const validateConfig = (config: SiteConfig): { valid: boolean; errors: string[] } => {
  const errors: string[] = []

  if (!config.serverHost) {
    errors.push("serverHost is required")
  }

  if (!config.api?.baseURL) {
    errors.push("api.baseURL is required")
  }

  if (!config.s3?.endpoint) {
    errors.push("s3.endpoint is required")
  }

  if (!config.s3?.region) {
    errors.push("s3.region is required")
  }

  return {
    valid: errors.length === 0,
    errors,
  }
}
