import { authService, state } from '../state.js';
import { loadProfileSnapshot } from './user-profile-params.js';
import { buildAvatarInitials as buildAvatarInitialsFromComponent } from '../components/avatar-image.js';

function normalizeLogin(value) {
  return String(value || '').trim();
}

function normKey(value) {
  return normalizeLogin(value).toLowerCase();
}

function uniqueLogins(list) {
  const out = [];
  const seen = new Set();
  (Array.isArray(list) ? list : []).forEach((item) => {
    const login = normalizeLogin(item);
    if (!login) return;
    const key = normKey(login);
    if (seen.has(key)) return;
    seen.add(key);
    out.push(login);
  });
  return out;
}

function listContainsLogin(list, login) {
  const targetKey = normKey(login);
  if (!targetKey) return false;
  return uniqueLogins(list).some((value) => normKey(value) === targetKey);
}

function toFieldMap(snapshot) {
  const map = {};
  (snapshot?.fields || []).forEach((field) => {
    map[field.key] = String(field.value || '').trim();
  });
  return map;
}

function toToggleMap(snapshot) {
  const map = {};
  (snapshot?.toggles || []).forEach((toggle) => {
    map[toggle.key] = Boolean(toggle.enabled);
  });
  return map;
}

function readArray(payload, key) {
  const aliases = {
    outKnownPersons: ['outKnownPersons', 'outKnownPerson', 'out_known_persons'],
    inKnownPersons: ['inKnownPersons', 'inKnownPerson', 'in_known_persons'],
    outShineConfirmed: ['outShineConfirmed', 'outShineConfident', 'out_shine_confirmed'],
    inShineConfirmed: ['inShineConfirmed', 'inShineConfident', 'in_shine_confirmed'],
    outShineSeen: ['outShineSeen', 'out_shine_seen'],
    inShineSeen: ['inShineSeen', 'in_shine_seen'],
  };
  const keys = aliases[key] || [key];
  let value = null;
  for (const oneKey of keys) {
    const candidate = payload?.[oneKey];
    if (Array.isArray(candidate)) {
      value = candidate;
      break;
    }
  }
  return Array.isArray(value) ? uniqueLogins(value) : null;
}

function feedOwnerLogins(feedPayload) {
  const rows = Array.isArray(feedPayload?.followedUsersChannels) ? feedPayload.followedUsersChannels : [];
  const owners = rows
    .map((row) => normalizeLogin(row?.channel?.ownerLogin))
    .filter(Boolean);
  return uniqueLogins(owners);
}

async function buildRelationsModel(login) {
  const cleanLogin = normalizeLogin(login);
  if (!cleanLogin) {
    return {
      outFriends: [],
      inFriends: [],
      outContacts: [],
      inContacts: [],
      outFollows: [],
      inFollows: [],
      outParents: [],
      inParents: [],
      outChildren: [],
      inChildren: [],
      outSiblings: [],
      inSiblings: [],
      outKnownPersons: [],
      inKnownPersons: [],
      outShineConfirmed: [],
      inShineConfirmed: [],
      outShineSeen: [],
      inShineSeen: [],
    };
  }

  const graph = await authService.getUserConnectionsGraph(cleanLogin);

  let outContacts = readArray(graph, 'outContacts');
  let outFollows = readArray(graph, 'outFollows');

  const isCurrentSessionLogin = normKey(cleanLogin) === normKey(state.session.login);

  if (outContacts === null && isCurrentSessionLogin) {
    try {
      const contacts = await authService.listContacts();
      outContacts = uniqueLogins(contacts?.contacts || []);
    } catch {
      outContacts = [];
    }
  }
  if (outContacts === null) outContacts = [];

  if (outFollows === null) {
    try {
      const feed = await authService.listSubscriptionsFeed(cleanLogin, 200);
      outFollows = feedOwnerLogins(feed);
    } catch {
      outFollows = [];
    }
  }

  return {
    outFriends: readArray(graph, 'outFriends') || [],
    inFriends: readArray(graph, 'inFriends') || [],
    outContacts,
    inContacts: readArray(graph, 'inContacts') || [],
    outFollows,
    inFollows: readArray(graph, 'inFollows') || [],
    outParents: readArray(graph, 'outParents') || [],
    inParents: readArray(graph, 'inParents') || [],
    outChildren: readArray(graph, 'outChildren') || [],
    inChildren: readArray(graph, 'inChildren') || [],
    outSiblings: readArray(graph, 'outSiblings') || [],
    inSiblings: readArray(graph, 'inSiblings') || [],
    outKnownPersons: readArray(graph, 'outKnownPersons') || [],
    inKnownPersons: readArray(graph, 'inKnownPersons') || [],
    outShineConfirmed: readArray(graph, 'outShineConfirmed') || [],
    inShineConfirmed: readArray(graph, 'inShineConfirmed') || [],
    outShineSeen: readArray(graph, 'outShineSeen') || [],
    inShineSeen: readArray(graph, 'inShineSeen') || [],
  };
}

export function buildIdentityLines({ login, firstName, lastName }) {
  const lines = [];
  const first = String(firstName || '').trim();
  const last = String(lastName || '').trim();
  const cleanLogin = normalizeLogin(login);

  if (first) lines.push(first);
  if (last) lines.push(last);
  lines.push(cleanLogin || 'unknown');

  return lines;
}

export const buildAvatarInitials = buildAvatarInitialsFromComponent;

export async function loadCurrentRelations() {
  const login = normalizeLogin(state.session.login);
  if (!login) {
    return {
      outFriends: [],
      inFriends: [],
      outContacts: [],
      inContacts: [],
      outFollows: [],
      inFollows: [],
      outParents: [],
      inParents: [],
      outChildren: [],
      inChildren: [],
      outSiblings: [],
      inSiblings: [],
      outKnownPersons: [],
      inKnownPersons: [],
      outShineConfirmed: [],
      inShineConfirmed: [],
      outShineSeen: [],
      inShineSeen: [],
    };
  }
  return buildRelationsModel(login);
}

export function relationFlagsForTarget(relations, targetLogin) {
  return {
    outFriend: listContainsLogin(relations?.outFriends, targetLogin),
    inFriend: listContainsLogin(relations?.inFriends, targetLogin),
    outContact: listContainsLogin(relations?.outContacts, targetLogin),
    inContact: listContainsLogin(relations?.inContacts, targetLogin),
    outFollow: listContainsLogin(relations?.outFollows, targetLogin),
    inFollow: listContainsLogin(relations?.inFollows, targetLogin),
    outParent: listContainsLogin(relations?.outParents, targetLogin),
    inParent: listContainsLogin(relations?.inParents, targetLogin),
    outChild: listContainsLogin(relations?.outChildren, targetLogin),
    inChild: listContainsLogin(relations?.inChildren, targetLogin),
    outSibling: listContainsLogin(relations?.outSiblings, targetLogin),
    inSibling: listContainsLogin(relations?.inSiblings, targetLogin),
    outKnownPerson: listContainsLogin(relations?.outKnownPersons, targetLogin),
    inKnownPerson: listContainsLogin(relations?.inKnownPersons, targetLogin),
    outShineConfirmed: listContainsLogin(relations?.outShineConfirmed, targetLogin),
    inShineConfirmed: listContainsLogin(relations?.inShineConfirmed, targetLogin),
    outShineSeen: listContainsLogin(relations?.outShineSeen, targetLogin),
    inShineSeen: listContainsLogin(relations?.inShineSeen, targetLogin),
  };
}

export async function loadUserProfileCard(login) {
  const cleanLogin = normalizeLogin(login);
  if (!cleanLogin) throw new Error('Пустой login');

  const [user, snapshot] = await Promise.all([
    authService.getUser(cleanLogin),
    loadProfileSnapshot(cleanLogin),
  ]);

  if (!user?.exists) throw new Error('Пользователь не найден');

  const canonicalLogin = normalizeLogin(user.login || cleanLogin);
  const fields = toFieldMap(snapshot);
  const toggles = toToggleMap(snapshot);

  return {
    login: canonicalLogin,
    blockchainName: normalizeLogin(user.blockchainName),
    firstName: fields.first_name || '',
    lastName: fields.last_name || '',
    address: fields.address || '',
    web: fields.web || '',
    phone: fields.phone || '',
    gender: String(snapshot?.gender || 'unknown').trim().toLowerCase() || 'unknown',
    official: Boolean(toggles.official),
    shine: Boolean(toggles.shine),
    avatar: snapshot?.avatar?.txId
      ? {
        ar: String(snapshot.avatar.txId).trim(),
        sha256Hex: String(snapshot?.avatar?.sha256Hex || '').trim().toLowerCase(),
      }
      : null,
  };
}

export async function loadRelationsForPair({ currentLogin, targetLogin }) {
  const cleanCurrent = normalizeLogin(currentLogin);
  const cleanTarget = normalizeLogin(targetLogin);
  const currentRelations = await buildRelationsModel(cleanCurrent);
  let flags = relationFlagsForTarget(currentRelations, cleanTarget);

  if (!flags.inContact || !flags.inFollow) {
    try {
      const targetRelations = await buildRelationsModel(cleanTarget);
      const backFlags = relationFlagsForTarget(targetRelations, cleanCurrent);
      flags = {
        ...flags,
        inContact: flags.inContact || backFlags.outContact,
        inFollow: flags.inFollow || backFlags.outFollow,
      };
    } catch {
      // ignore fallback failures for incoming direction
    }
  }

  return {
    ...flags,
    source: currentRelations,
  };
}
