import {
  getCloudtentaclesSourceByKey,
  getCloudtentaclesSourcesFilePath,
  listCloudtentaclesSources,
  saveCloudtentaclesSourceByKey,
  saveCloudtentaclesSourcesList,
  deleteCloudtentaclesSourceByKey,
} from "../../platforms/cloudtentacles/source-config-service.js";
import {
  clearCloudtentaclesSessionStateByKey,
  getCloudtentaclesSessionFilePath,
  getCloudtentaclesSessionStateByKey,
  saveCloudtentaclesSessionStateByKey,
  getAllCloudtentaclesSessionStates,
} from "../../platforms/cloudtentacles/session-state-service.js";
import {
  loginCloudtentaclesSession,
  sendCloudtentaclesSmsCode,
  validateCloudtentaclesSession,
} from "../../platforms/cloudtentacles/session-service.js";
import {
  buyCloudtentaclesSku,
  getCloudtentaclesAsset,
  getCloudtentaclesCategories,
  listCloudtentaclesSku,
  useCloudtentaclesSku,
} from "../../platforms/cloudtentacles/catalog-service.js";
import { getCloudtentaclesKnapsack } from "../../platforms/cloudtentacles/knapsack-service.js";
import {
  appointCloudtentaclesVirtualNumber,
  backCloudtentaclesVirtualNumber,
  fetchCloudtentaclesVirtualNumberCode,
  generateCloudtentaclesLoginCode,
  getCloudtentaclesBindUrl,
  listCloudtentaclesVirtualNumbers,
  verifyCloudtentaclesLoginCode,
} from "../../platforms/cloudtentacles/virtual-number-service.js";
import { runCloudtentaclesFullDebugFlow } from "../../platforms/cloudtentacles/debug-flow-service.js";
import {
  hasCloudtentaclesCredentialContextChanged,
  pickFirstNonEmpty,
} from "./context.js";
import {
  buildAdminCloudtentaclesLoginResult,
  buildAdminCloudtentaclesPersistedSessionPayload,
  buildAdminCloudtentaclesValidateResult,
  resolveAdminCloudtentaclesCredentialPayload,
  resolveAdminCloudtentaclesSessionPayload,
} from "./cloudtentacles.js";
import { normalizeAdminCloudtentaclesSourceConfigPayload } from "./writes.js";
import {
  mapAdminCloudtentaclesSession,
  mapAdminCloudtentaclesSourceConfig,
  maskPhone,
} from "./mappers.js";

import type {
  AdminCloudtentaclesCatalogQueryInput,
  AdminCloudtentaclesFullFlowInput,
  AdminCloudtentaclesSendSmsCodeInput,
  AdminCloudtentaclesSkuBuyInput,
  AdminCloudtentaclesSkuUseInput,
  AdminCloudtentaclesSourceConfigInput,
  AdminCloudtentaclesTestLoginInput,
  AdminCloudtentaclesValidateSessionInput,
  AdminCloudtentaclesVirtualNumberInput,
} from "../../../types/admin-write-inputs.js";

type JsonObject = Record<string, any>;

export function listAdminCloudtentaclesSources() {
  const list = listCloudtentaclesSources();
  const sessions = getAllCloudtentaclesSessionStates();

  const sources = Array.isArray(list.sources)
    ? list.sources.map((s) => mapAdminCloudtentaclesSourceConfig(s))
    : [];

  const mappedSessions: JsonObject = {};
  for (const [key, session] of Object.entries(sessions.sessions || {})) {
    mappedSessions[key] = mapAdminCloudtentaclesSession(session);
  }

  return {
    filePath: getCloudtentaclesSourcesFilePath(),
    sessionFilePath: getCloudtentaclesSessionFilePath(),
    enabled: list.enabled,
    sources,
    sessions: mappedSessions,
  };
}

export function updateAdminCloudtentaclesSourceConfig(
  payload: AdminCloudtentaclesSourceConfigInput = {}
) {
  // Batch save: if payload.sources is an array, save the whole list
  if (Array.isArray(payload.sources)) {
    const normalizedList = payload.sources.map((item) =>
      normalizeAdminCloudtentaclesSourceConfigPayload(item)
    );
    const savedList = saveCloudtentaclesSourcesList({
      enabled: payload.enabled !== false,
      sources: normalizedList,
    });
    const sessions = getAllCloudtentaclesSessionStates();

    const sources = Array.isArray(savedList.sources)
      ? savedList.sources.map((s) => mapAdminCloudtentaclesSourceConfig(s))
      : [];
    const mappedSessions: JsonObject = {};
    for (const [key, session] of Object.entries(sessions.sessions || {})) {
      mappedSessions[key] = mapAdminCloudtentaclesSession(session);
    }

    return {
      filePath: getCloudtentaclesSourcesFilePath(),
      sessionFilePath: getCloudtentaclesSessionFilePath(),
      enabled: savedList.enabled,
      sources,
      sessions: mappedSessions,
    };
  }

  // Single source save
  const sourceKey = String(payload.sourceKey || "").trim() || "default";
  const current = getCloudtentaclesSourceByKey(sourceKey);
  const normalized = normalizeAdminCloudtentaclesSourceConfigPayload({
    ...payload,
    sourceKey,
  });
  const saved = saveCloudtentaclesSourceByKey(sourceKey, normalized);
  const shouldClearSession = hasCloudtentaclesCredentialContextChanged(
    current,
    saved
  );
  const session = shouldClearSession
    ? (clearCloudtentaclesSessionStateByKey(sourceKey),
      getCloudtentaclesSessionStateByKey(sourceKey))
    : getCloudtentaclesSessionStateByKey(sourceKey);

  return {
    filePath: getCloudtentaclesSourcesFilePath(),
    sessionFilePath: getCloudtentaclesSessionFilePath(),
    source: mapAdminCloudtentaclesSourceConfig(saved),
    session: mapAdminCloudtentaclesSession(session),
  };
}

export function deleteAdminCloudtentaclesSource(sourceKey: string) {
  const key = String(sourceKey || "").trim();
  if (!key) {
    throw new Error("sourceKey is required for deletion");
  }
  clearCloudtentaclesSessionStateByKey(key);
  deleteCloudtentaclesSourceByKey(key);
}

export async function sendAdminCloudtentaclesSmsCode(
  payload: AdminCloudtentaclesSendSmsCodeInput = {}
) {
  const result = await sendCloudtentaclesSmsCode(
    resolveAdminCloudtentaclesCredentialPayload(payload)
  );

  return {
    ...result,
    phoneMasked: maskPhone(result.phone),
  };
}

export async function testAdminCloudtentaclesLogin(
  payload: AdminCloudtentaclesTestLoginInput = {}
) {
  const sourceKey = String(payload.sourceKey || "").trim() || "default";
  const savedSource = getCloudtentaclesSourceByKey(sourceKey) || {};
  const credentialContext = resolveAdminCloudtentaclesCredentialPayload(
    payload,
    { savedSource }
  );
  const session = await loginCloudtentaclesSession({
    ...credentialContext,
    code: String(payload.code || "").trim(),
  });
  const savedSession = saveCloudtentaclesSessionStateByKey(
    sourceKey,
    buildAdminCloudtentaclesPersistedSessionPayload(session, {
      deviceId: credentialContext.deviceId,
      deviceType: credentialContext.deviceType,
    })
  );

  return buildAdminCloudtentaclesLoginResult(session, savedSession, sourceKey);
}

export async function validateAdminCloudtentaclesSession(
  payload: AdminCloudtentaclesValidateSessionInput = {}
) {
  const sourceKey = String(payload.sourceKey || "").trim() || "default";
  const savedSource: JsonObject = getCloudtentaclesSourceByKey(sourceKey) || {};
  const persistedSession: JsonObject = getCloudtentaclesSessionStateByKey(sourceKey) || {};
  const sessionContext = resolveAdminCloudtentaclesSessionPayload(payload, {
    savedSource,
    persistedSession,
  });
  const session = await validateCloudtentaclesSession(sessionContext);
  const savedSession = saveCloudtentaclesSessionStateByKey(
    sourceKey,
    buildAdminCloudtentaclesPersistedSessionPayload(session, {
      username: pickFirstNonEmpty([
        persistedSession.username,
        savedSource.username,
      ]),
      phone: pickFirstNonEmpty([persistedSession.phone, savedSource.phone]),
      deviceId: sessionContext.deviceId,
      deviceType: sessionContext.deviceType,
    })
  );

  return buildAdminCloudtentaclesValidateResult(
    session,
    savedSession,
    sourceKey
  );
}

export async function getAdminCloudtentaclesAsset(
  payload: AdminCloudtentaclesCatalogQueryInput = {}
) {
  return getCloudtentaclesAsset(
    resolveAdminCloudtentaclesSessionPayload(payload)
  );
}

export async function getAdminCloudtentaclesCategories(
  payload: AdminCloudtentaclesCatalogQueryInput = {}
) {
  return getCloudtentaclesCategories(
    resolveAdminCloudtentaclesSessionPayload(payload)
  );
}

export async function getAdminCloudtentaclesSkuList(
  payload: AdminCloudtentaclesCatalogQueryInput = {}
) {
  return listCloudtentaclesSku(
    resolveAdminCloudtentaclesSessionPayload(payload)
  );
}

export async function buyAdminCloudtentaclesSku(
  payload: AdminCloudtentaclesSkuBuyInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return buyCloudtentaclesSku({
    ...context,
    id: payload.id,
    count: payload.count,
  });
}

export async function useAdminCloudtentaclesSku(
  payload: AdminCloudtentaclesSkuUseInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return useCloudtentaclesSku({
    ...context,
    id: payload.id,
    virtualNumberId: payload.virtualNumberId,
    phone: payload.phone,
  });
}

export async function getAdminCloudtentaclesKnapsack(
  payload: AdminCloudtentaclesCatalogQueryInput = {}
) {
  return getCloudtentaclesKnapsack(
    resolveAdminCloudtentaclesSessionPayload(payload)
  );
}

export async function listAdminCloudtentaclesVirtualNumbers(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return listCloudtentaclesVirtualNumbers({
    ...context,
    key: payload.key,
  });
}

export async function appointAdminCloudtentaclesVirtualNumber(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return appointCloudtentaclesVirtualNumber({
    ...context,
    key: payload.key,
  });
}

export async function generateAdminCloudtentaclesLoginCode(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return generateCloudtentaclesLoginCode({
    ...context,
    key: payload.key,
    id: payload.id,
  });
}

export async function fetchAdminCloudtentaclesVirtualNumberCode(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return fetchCloudtentaclesVirtualNumberCode({
    ...context,
    key: payload.key,
    phone: payload.phone,
  });
}

export async function verifyAdminCloudtentaclesLoginCode(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return verifyCloudtentaclesLoginCode({
    ...context,
    key: payload.key,
    id: payload.id,
    code: payload.code,
  });
}

export async function getAdminCloudtentaclesBindUrl(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return getCloudtentaclesBindUrl({
    ...context,
    key: payload.key,
    id: payload.id,
  });
}

export async function backAdminCloudtentaclesVirtualNumber(
  payload: AdminCloudtentaclesVirtualNumberInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return backCloudtentaclesVirtualNumber({
    ...context,
    key: payload.key,
    id: payload.id,
  });
}

export async function runAdminCloudtentaclesFullFlow(
  payload: AdminCloudtentaclesFullFlowInput = {}
) {
  const context = resolveAdminCloudtentaclesSessionPayload(payload);
  return runCloudtentaclesFullDebugFlow({
    ...context,
    skuId: payload.skuId,
    skuCount: payload.skuCount,
    vnKey: payload.vnKey,
  });
}
