import { ALWAYS_SELECTED_DOC_TYPES, FIELD_ORDERS_DEFAULTS_LS, FIELD_SELECTIONS_DEFAULTS_LS, INDIVIDUAL_NUMBER_AUTO_INCREMENT_DEFAULT_LS } from '../config/constants.js';
import { fieldsByKindConfig } from '../config/fields-config.js';
import { readLs } from '../core/storage.js';
import { getCurrentProjectKind, getWorkHeaderDisplayFields, normalizeDocTypeKey } from './project-context.js';
import { state, userPrefsStore } from '../state/app-state.js';

export function isAlwaysSelectedDocType(docTypeName) {
  return ALWAYS_SELECTED_DOC_TYPES.has(normalizeDocTypeKey(docTypeName));
}


export function isFieldDefaultSelected(docTypeName, field) {
  if (isAlwaysSelectedDocType(docTypeName)) return true;
  return !!(field && field.defaultSelected);
}


export function buildDefaultFieldSelections() {
  const defaults = {};
  Object.entries(fieldsByKindConfig).forEach(([kind, byDocType]) => {
    Object.entries(byDocType || {}).forEach(([docType, fields]) => {
      (Array.isArray(fields) ? fields : []).forEach((field) => {
        const key = buildFieldSelectionKey(kind, docType, field.fieldName || "");
        defaults[key] = isFieldDefaultSelected(docType, field);
      });
    });
  });
  return defaults;
}

export const DEFAULT_FIELD_SELECTIONS = buildDefaultFieldSelections();

export function cloneDefaultFieldSelections() {
  return { ...DEFAULT_FIELD_SELECTIONS };
}


export function mergeFieldSelectionsFromParsed(target, parsed) {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return target;
  Object.entries(parsed).forEach(([key, value]) => {
    target[key] = !!value;
  });
  return target;
}


export function mergeFieldOrdersFromParsed(target, parsed) {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return target;
  Object.entries(parsed).forEach(([orderKey, order]) => {
    if (!Array.isArray(order)) return;
    target[orderKey] = order.map((id) => String(id));
  });
  return target;
}


export function loadSavedFieldSelectionDefaultsFromLocalStorage() {
  const defaults = cloneDefaultFieldSelections();
  try {
    const raw = readLs(FIELD_SELECTIONS_DEFAULTS_LS);
    if (!raw) return defaults;
    return mergeFieldSelectionsFromParsed(defaults, JSON.parse(raw));
  } catch (_) {}
  return defaults;
}


export function loadSavedFieldSelectionDefaults(storedDefaults) {
  const defaults = cloneDefaultFieldSelections();
  if (storedDefaults) {
    return mergeFieldSelectionsFromParsed(defaults, storedDefaults);
  }
  return loadSavedFieldSelectionDefaultsFromLocalStorage();
}


export function buildFieldOrderStorageKey(kind, docType) {
  return [
    String(kind || "").trim(),
    normalizeDocTypeKey(docType),
  ].join("::");
}


export function getFieldOrderId(field, index) {
  return [
    String(field && field.fieldName ? field.fieldName : ""),
    String(field && field.fieldLabel ? field.fieldLabel : ""),
    String(index),
  ].join("::");
}


export function buildFieldEntries(fields) {
  return (Array.isArray(fields) ? fields : []).map((field, index) => ({
    field,
    index,
    id: getFieldOrderId(field, index),
  }));
}


export function buildDefaultFieldOrders() {
  const defaults = {};
  Object.entries(fieldsByKindConfig).forEach(([kind, byDocType]) => {
    Object.entries(byDocType || {}).forEach(([docType, fields]) => {
      const orderKey = buildFieldOrderStorageKey(kind, docType);
      defaults[orderKey] = buildFieldEntries(fields).map((entry) => entry.id);
    });
  });
  return defaults;
}

export const DEFAULT_FIELD_ORDERS = buildDefaultFieldOrders();


export function cloneDefaultFieldOrders() {
  const cloned = {};
  Object.keys(DEFAULT_FIELD_ORDERS).forEach((key) => {
    cloned[key] = Array.isArray(DEFAULT_FIELD_ORDERS[key]) ? [...DEFAULT_FIELD_ORDERS[key]] : [];
  });
  return cloned;
}


export function loadSavedFieldOrderDefaultsFromLocalStorage() {
  const defaults = cloneDefaultFieldOrders();
  try {
    const raw = readLs(FIELD_ORDERS_DEFAULTS_LS);
    if (!raw) return defaults;
    const parsed = JSON.parse(raw);
    mergeFieldOrdersFromParsed(defaults, parsed);
    Object.entries(fieldsByKindConfig).forEach(([kind, byDocType]) => {
      Object.entries(byDocType || {}).forEach(([docType, fields]) => {
        const orderKey = buildFieldOrderStorageKey(kind, docType);
        const entries = buildFieldEntries(fields);
        defaults[orderKey] = normalizeFieldOrderForEntries(defaults[orderKey], entries);
      });
    });
  } catch (_) {}
  return defaults;
}


export function loadSavedFieldOrderDefaults(storedDefaults) {
  const defaults = cloneDefaultFieldOrders();
  if (storedDefaults) {
    mergeFieldOrdersFromParsed(defaults, storedDefaults);
    Object.entries(fieldsByKindConfig).forEach(([kind, byDocType]) => {
      Object.entries(byDocType || {}).forEach(([docType, fields]) => {
        const orderKey = buildFieldOrderStorageKey(kind, docType);
        const entries = buildFieldEntries(fields);
        defaults[orderKey] = normalizeFieldOrderForEntries(defaults[orderKey], entries);
      });
    });
    return defaults;
  }
  return loadSavedFieldOrderDefaultsFromLocalStorage();
}


export function getDefaultIndividualNumberAutoIncrement(storedValue) {
  if (storedValue === true) return true;
  if (storedValue === false) return false;
  if (userPrefsStore.individual_number_auto_increment_default === true) return true;
  if (userPrefsStore.individual_number_auto_increment_default === false) return false;
  return readLs(INDIVIDUAL_NUMBER_AUTO_INCREMENT_DEFAULT_LS) === "1";
}


export function normalizeFieldOrderForEntries(order, entries) {
  const ids = entries.map((entry) => entry.id);
  if (!Array.isArray(order)) return [...ids];
  const validIds = new Set(ids);
  const seen = new Set();
  const normalized = [];
  order.forEach((id) => {
    if (!validIds.has(id) || seen.has(id)) return;
    seen.add(id);
    normalized.push(id);
  });
  ids.forEach((id) => {
    if (seen.has(id)) return;
    seen.add(id);
    normalized.push(id);
  });
  return normalized;
}


export function getOrderedFieldEntries(kind, docType, fields) {
  const entries = buildFieldEntries(fields);
  const orderKey = buildFieldOrderStorageKey(kind, docType);
  const sourceOrder = state.fieldOrders[orderKey];
  const normalizedOrder = normalizeFieldOrderForEntries(sourceOrder, entries);
  const byId = new Map(entries.map((entry) => [entry.id, entry]));
  return normalizedOrder.map((id) => byId.get(id)).filter(Boolean);
}


export function buildFieldSelectionKey(kind, docType, fieldName) {
  return [
    String(kind || "").trim(),
    normalizeDocTypeKey(docType),
    String(fieldName || "").trim(),
  ].join("::");
}


export function isWorkHeaderFieldSelected(baseFieldName) {
  const kind = getCurrentProjectKind();
  const key = buildFieldSelectionKey(kind, "__HEADER__", baseFieldName);
  if (Object.prototype.hasOwnProperty.call(state.fieldSelections, key)) {
    return !!state.fieldSelections[key];
  }
  const def = getWorkHeaderDisplayFields(kind).find(
    (f) => String(f.fieldName) === String(baseFieldName || "")
  );
  return !!(def && def.defaultSelected);
}
