import { normalizeWhatsAppId } from '../../utils/whatsapp';
import { IdentityService } from '../identity';

/**
 * Parse a participants array (strings or objects) from Evolution API into
 * normalized {userId, isAdmin} entries, including identity resolution.
 */
function parseParticipants(participants: any[]): Array<{ userId: string; isAdmin: boolean }> {
  const result: Array<{ userId: string; isAdmin: boolean }> = [];
  for (const p of participants) {
    let jid: string | null = null;
    let isAdmin = false;

    if (typeof p === 'string') {
      jid = p;
    } else if (p && typeof p === 'object') {
      const rawId = p.id || p?.user?.id || p.user || null;
      const rawJid = p.jid || null;
      jid = rawJid || rawId || null;

      if (rawId && rawJid) {
        try { IdentityService.upsertAlias(String(rawId), String(rawJid), 'group.participants'); } catch {}
      }

      if (typeof p.isAdmin === 'boolean') {
        isAdmin = p.isAdmin;
      } else if (typeof p.admin === 'string') {
        isAdmin = p.admin === 'admin' || p.admin === 'superadmin';
      } else if (typeof p.role === 'string') {
        isAdmin = p.role.toLowerCase().includes('admin');
      }
    }

    let norm = normalizeWhatsAppId(jid);
    if (!norm) {
      const digits = (jid || '').replace(/\D+/g, '');
      norm = digits || null;
    }
    if (!norm) continue;
    result.push({ userId: norm, isAdmin });
  }

  // Resolve identities
  try {
    const map = IdentityService.resolveMany(result.map(r => r.userId));
    return result.map(r => ({ userId: map.get(r.userId) || r.userId, isAdmin: r.isAdmin }));
  } catch {
    return result;
  }
}

export type ApiEvolutionGroup = {
  id: string;
  subject: string;
  linkedParent?: string;
  // flags que pueden venir en la API y usamos para filtrar comunidades/announce
  isCommunity?: any;
  is_community?: any;
  isCommunityAnnounce?: any;
  is_community_announce?: any;
};

/**
 * Obtiene todos los grupos desde Evolution API.
 * Acepta respuesta como array directo o envuelta { status, response }.
 */
export async function fetchGroupsFromAPI(): Promise<ApiEvolutionGroup[]> {
  const url = `${process.env.EVOLUTION_API_URL}/group/fetchAllGroups/${process.env.EVOLUTION_API_INSTANCE}?getParticipants=false`;
  console.log('ℹ️ Fetching groups from API:', {
    url: `${url}...`,
    communityId: process.env.WHATSAPP_COMMUNITY_ID,
    time: new Date().toISOString()
  });

  try {
    const response = await fetch(url, {
      method: 'GET',
      headers: { apikey: String(process.env.EVOLUTION_API_KEY || '') },
      httpVersion: '2',
      timeout: 320000
    });

    if (!response.ok) {
      const errorBody = await response.text().catch(() => 'Unable to read error body');
      console.error('❌ API request failed:', {
        status: response.status,
        statusText: response.statusText,
        headers: Object.fromEntries(response.headers.entries()),
        body: errorBody
      });
      throw new Error(`API request failed: ${response.status} ${response.statusText}`);
    }

    const rawResponse = await response.text();
    console.log('ℹ️ Raw API response length:', rawResponse.length);

    let groups: ApiEvolutionGroup[] = [];
    try {
      const parsed = JSON.parse(rawResponse);
      if (Array.isArray(parsed)) {
        groups = parsed as ApiEvolutionGroup[];
        console.log('ℹ️ Received direct array of', groups.length, 'groups');
      } else if (parsed?.response && Array.isArray(parsed.response)) {
        if (parsed.status !== 'success') {
          throw new Error(`API error: ${parsed.message || 'Unknown error'}`);
        }
        groups = parsed.response as ApiEvolutionGroup[];
        console.log('ℹ️ Received wrapped response with', groups.length, 'groups');
      } else {
        throw new Error('Invalid API response format - expected array or wrapped response');
      }
    } catch (e) {
      console.error('❌ Failed to parse API response:', {
        error: e instanceof Error ? e.message : String(e),
        responseSample: rawResponse.substring(0, 100) + '...'
      });
      throw e;
    }

    if (!groups.length) {
      console.warn('⚠️ API returned empty group list');
    }
    return groups;
  } catch (error) {
    console.error('❌ Failed to fetch groups:', {
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined
    });
    throw error;
  }
}

// Cooldown global simple para 429 de miembros
let membersGlobalCooldownUntil = 0;

/**
 * Obtiene miembros de un grupo desde Evolution API, con parser robusto y fallback a fetchAllGroups.
 */
export async function fetchGroupMembersFromAPI(groupId: string): Promise<Array<{ userId: string; isAdmin: boolean }>> {
  try {
    if (membersGlobalCooldownUntil && Date.now() < membersGlobalCooldownUntil) {
      console.warn('⚠️ Skipping members fetch due to global cooldown');
      return [];
    }
  } catch {}

  // 1) Endpoint preferente: /group/participants
  try {
    const url1 = `${process.env.EVOLUTION_API_URL}/group/participants/${process.env.EVOLUTION_API_INSTANCE}?groupJid=${encodeURIComponent(groupId)}`;
    console.log('ℹ️ Fetching members via /group/participants:', { groupId });

    const r1 = await fetch(url1, {
      method: 'GET',
      headers: { apikey: String(process.env.EVOLUTION_API_KEY || '') },
      httpVersion: '2',
      timeout: 320000
    });

    if (r1.ok) {
      const raw1 = await r1.text();
      let parsed1: any;
      try {
        parsed1 = JSON.parse(raw1);
      } catch (e) {
        console.error('❌ Failed to parse /group/participants JSON:', String(e));
        throw e;
      }

      const participantsArr = Array.isArray(parsed1?.participants) ? parsed1.participants : null;
      if (participantsArr) {
        return parseParticipants(participantsArr);
      }
      console.warn('⚠️ /group/participants responded without participants array, falling back to fetchAllGroups');
    } else {
      const body = await r1.text().catch(() => '');
      if (r1.status === 429) {
        console.warn(`⚠️ /group/participants rate-limited (429): ${body.slice(0, 200)}`);
        membersGlobalCooldownUntil = Date.now() + 2 * 60 * 1000;
        return [];
      }
      console.warn(`⚠️ /group/participants failed: ${r1.status} ${r1.statusText} - ${body.slice(0, 200)}. Falling back to fetchAllGroups`);
    }
  } catch (e) {
    console.warn('⚠️ Error calling /group/participants, falling back to fetchAllGroups:', e instanceof Error ? e.message : String(e));
  }

  // 2) Fallback: fetchAllGroups(getParticipants=true)
  const url = `${process.env.EVOLUTION_API_URL}/group/fetchAllGroups/${process.env.EVOLUTION_API_INSTANCE}?getParticipants=true`;
  console.log('ℹ️ Fetching members via fetchAllGroups (participants=true):', { groupId });

  const response = await fetch(url, {
    method: 'GET',
    headers: { apikey: String(process.env.EVOLUTION_API_KEY || '') },
    httpVersion: '2',
    timeout: 320000
  });
  if (!response.ok) {
    const body = await response.text().catch(() => '');
    if (response.status === 429) {
      console.warn(`⚠️ fetchAllGroups(getParticipants=true) rate-limited (429): ${body.slice(0, 200)}`);
      membersGlobalCooldownUntil = Date.now() + 2 * 60 * 1000;
      return [];
    }
    throw new Error(`Failed to fetch groups with participants: ${response.status} ${response.statusText} - ${body.slice(0,200)}`);
  }
  const raw = await response.text();
  let parsed: any;
  try {
    parsed = JSON.parse(raw);
  } catch (e) {
    console.error('❌ Failed to parse members response JSON:', String(e));
    throw e;
  }

  let groups: any[] = [];
  if (Array.isArray(parsed)) {
    groups = parsed;
  } else if (parsed && Array.isArray(parsed.response)) {
    groups = parsed.response;
  } else {
    throw new Error('Invalid response format for groups with participants');
  }

  const g = groups.find((g: any) => g?.id === groupId);
  if (!g) {
    console.warn(`⚠️ Group ${groupId} not present in fetchAllGroups(getParticipants=true) response`);
    return [];
  }
  const participants = Array.isArray(g.participants) ? g.participants : [];
  return parseParticipants(participants);
}
