import fs from 'node:fs'
import path from 'node:path'

import { PROJECT_ROOT } from '../../../config/runtime.js'

const CLOUDTENTACLES_SESSION_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-session.json')

type JsonObject = Record<string, any>

export function getCloudtentaclesSessionFilePath() {
  return CLOUDTENTACLES_SESSION_FILE_PATH
}

/**
 * Backward-compatible: returns the session for key='default'.
 * Old callers that expect a single session object still work.
 */
export function getCloudtentaclesSessionState() {
  const states = loadCloudtentaclesSessionStatesFromFile()
  return states.sessions['default'] || createDefaultCloudtentaclesSessionState()
}

/**
 * Get a session by its sourceKey. Returns null if not found.
 */
export function getCloudtentaclesSessionStateByKey(sourceKey: unknown) {
  const states = loadCloudtentaclesSessionStatesFromFile()
  const key = String(sourceKey || '').trim()
  if (!key) return null
  return states.sessions[key] || null
}

/**
 * Return the entire session states map: { sessions: { 'default': {...}, ... } }.
 */
export function getAllCloudtentaclesSessionStates() {
  return loadCloudtentaclesSessionStatesFromFile()
}

/**
 * Backward-compatible save: accepts both old single-object format
 * and new sessions-map format, normalizes, and persists.
 */
export function saveCloudtentaclesSessionState(rawValue: unknown) {
  const normalized = normalizeSessionStatesFile(rawValue)
  fs.mkdirSync(path.dirname(CLOUDTENTACLES_SESSION_FILE_PATH), { recursive: true })
  fs.writeFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
  return normalized.sessions['default'] || createDefaultCloudtentaclesSessionState()
}

/**
 * Save a session for a specific sourceKey.
 */
export function saveCloudtentaclesSessionStateByKey(sourceKey: unknown, rawValue: unknown) {
  const key = String(sourceKey || '').trim()
  if (!key) {
    throw new Error('saveCloudtentaclesSessionStateByKey: sourceKey is required')
  }

  const states = loadCloudtentaclesSessionStatesFromFile()
  states.sessions[key] = normalizeCloudtentaclesSessionState(rawValue)

  fs.mkdirSync(path.dirname(CLOUDTENTACLES_SESSION_FILE_PATH), { recursive: true })
  fs.writeFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, `${JSON.stringify(states, null, 2)}\n`, 'utf8')
  return states.sessions[key]
}

/**
 * Backward-compatible clear: clears the 'default' session only.
 */
export function clearCloudtentaclesSessionState() {
  return clearCloudtentaclesSessionStateByKey('default')
}

/**
 * Clear a session by sourceKey (sets it to default empty state).
 */
export function clearCloudtentaclesSessionStateByKey(sourceKey: unknown) {
  const key = String(sourceKey || '').trim()
  if (!key) {
    throw new Error('clearCloudtentaclesSessionStateByKey: sourceKey is required')
  }

  const cleared = createDefaultCloudtentaclesSessionState()
  saveCloudtentaclesSessionStateByKey(key, cleared)
  return cleared
}

// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------

function loadCloudtentaclesSessionStatesFromFile() {
  if (!fs.existsSync(CLOUDTENTACLES_SESSION_FILE_PATH)) {
    return createDefaultCloudtentaclesSessionStates()
  }

  try {
    const rawText = fs.readFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, 'utf8')
    return normalizeSessionStatesFile(JSON.parse(rawText))
  } catch {
    return createDefaultCloudtentaclesSessionStates()
  }
}

/**
 * Normalize a single session state item.
 */
function normalizeCloudtentaclesSessionState(rawValue: unknown) {
  const source = isPlainObject(rawValue) ? rawValue : {}

  return {
    token: String(source.token || '').trim(),
    baseUrl: String(source.baseUrl || '').trim(),
    username: String(source.username || '').trim(),
    phone: String(source.phone || '').trim(),
    loggedInAt: String(source.loggedInAt || '').trim(),
    deviceId: String(source.deviceId || '-').trim() || '-',
    deviceType: normalizeInteger(source.deviceType, 0),
  }
}

/**
 * Normalize the overall session states file format.
 * Handles old format (single object without sessions key) by auto-wrapping
 * into { sessions: { 'default': ... } }.
 */
function normalizeSessionStatesFile(rawValue: unknown) {
  // Old format: { token: 'xxx', ... } (single object, no sessions key)
  if (isPlainObject(rawValue) && !rawValue.sessions) {
    return {
      sessions: {
        'default': normalizeCloudtentaclesSessionState(rawValue),
      },
    }
  }

  // New format: { sessions: { 'default': {...}, ... } }
  return {
    sessions: isPlainObject(rawValue) && isPlainObject(rawValue.sessions)
      ? Object.fromEntries(
          Object.entries(rawValue.sessions).map(([k, v]) => [k, normalizeCloudtentaclesSessionState(v)])
        )
      : {},
  }
}

function createDefaultCloudtentaclesSessionState() {
  return {
    token: '',
    baseUrl: '',
    username: '',
    phone: '',
    loggedInAt: '',
    deviceId: '-',
    deviceType: 0,
  }
}

function createDefaultCloudtentaclesSessionStates() {
  return {
    sessions: {
      'default': createDefaultCloudtentaclesSessionState(),
    },
  }
}

function normalizeInteger(value: unknown, fallback: number) {
  const parsed = Number(value)
  return Number.isInteger(parsed) ? parsed : fallback
}

function isPlainObject(value: unknown): value is JsonObject {
  return Object.prototype.toString.call(value) === '[object Object]'
}
