import { CometChat } from '@cometchat/chat-sdk-javascript';
import ChatCustomFetch from '@/Utils/APIRequest/ChatAxiosInstance';
import { ChatConversations } from '@/Utils/APIRequest/Endpoints';
import {
  ALL_STAGE_KEYS,
  conversationCountsTowardUnreadFilter,
  getConversationMessagePreview,
  getTagsForFilter,
  inferStageFromChatMessage,
  isActionUnreadEvent,
  isBrandOwnedActionMessage,
  looksLikeBrandActionPreview,
  statusFromTags,
  WORKING_STAGES,
} from './stageUtils';

/** UI page size for local scroll pagination */
export const CONVERSATIONS_PAGE_SIZE = 30;

/** Fetch once from REST (SDK max is 50; API allows up to 1000) */
export const CONVERSATIONS_API_LIMIT = 1000;

export type MappedConversation = {
  id: string;
  status: string;
  tags: string[];
  message: string;
  updatedAt: number;
  unreadMessageCount: number;
  /** Pending action for filter badge (draft / quotation / completion) — 1 per person */
  actionUnreadStage?: string | null;
  influencer: {
    id?: string | number;
    display_name?: string;
    first_name?: string;
    image?: string;
  };
  campaign: {
    id?: string | number;
    campaign_name?: string;
    slug?: string;
  };
  conversationWith?: any;
};

/** Update list-row stage tag/status (e.g. after approve quote / draft / completion). */
export const withConversationStatus = (
  item: MappedConversation,
  status: string
): MappedConversation => {
  if (!item || !status || item.status === status) return item;
  const cleaned = (Array.isArray(item.tags) ? item.tags : []).filter(
    (t) => !(ALL_STAGE_KEYS as readonly string[]).includes(t)
  );
  return {
    ...item,
    status,
    tags: [...cleaned, status],
    actionUnreadStage: null,
    unreadMessageCount: 0,
  };
};

const normalizeSentAt = (ts: any): number => {
  const n = Number(ts);
  if (!n || Number.isNaN(n)) return 0;
  return n > 1e12 ? Math.floor(n / 1000) : n;
};

const asStringArray = (tags: unknown): string[] => {
  if (!Array.isArray(tags)) return [];
  return tags.map((t) => String(t)).filter(Boolean);
};

const extractTags = (conversation: any): string[] => {
  const tags = conversation?.conversationWith?.tags || [];
  return asStringArray(tags);
};

const STAGE_TAG_SET = new Set<string>(ALL_STAGE_KEYS as readonly string[]);

/** Campaign id lives in tags alongside status (e.g. [campaignUuid, "waiting_for_quotations"]). */
export const campaignIdFromTags = (tags: string[]): string | undefined => {
  const found = tags.find((t) => t && !STAGE_TAG_SET.has(t));
  return found || undefined;
};

export const matchesCampaign = (
  item: MappedConversation,
  campaignId?: string | number | null
) => {
  if (campaignId == null || campaignId === '' || campaignId === 'all') return true;
  const id = String(campaignId);
  if (String(item.campaign?.id || '') === id) return true;
  if (item.tags?.includes(id)) return true;
  return false;
};

const isPlaceholderImage = (url?: string) => {
  if (!url) return true;
  return /placeholder/i.test(url);
};

export const mapCometConversation = (conversation: any): MappedConversation | null => {
  if (!conversation) return null;

  const guid = String(conversation?.conversationWith?.guid).replace(/^group_/, '');
  if (!guid) return null;

  const group = conversation?.conversationWith || {};
  const meta = group?.metadata && typeof group.metadata === 'object' ? group.metadata : {};
  const tags = extractTags(conversation);

  const status = statusFromTags(tags) || statusFromTags(meta?.status ? [String(meta.status)] : [])

  const text = getConversationMessagePreview(conversation?.lastMessage);

  const campaignId = meta.campaign_id

  const influencerId = meta?.influencer?.id;

  const rawIcon = group?.icon;
  const image = isPlaceholderImage(rawIcon) ? undefined : rawIcon;

  const lastMessage = conversation?.lastMessage;
  const brandActed =
    looksLikeBrandActionPreview(text) || isBrandOwnedActionMessage(lastMessage);
  const unreadMessageCount = brandActed
    ? 0
    : Number(conversation?.unreadMessageCount || 0);
  // Quotation / Draft Ready / Completion submit while still unread → filter + list badge
  const actionUnreadStage =
    !brandActed &&
      unreadMessageCount > 0 &&
      isActionUnreadEvent(lastMessage)
      ? inferStageFromChatMessage(lastMessage)
      : null;

  return {
    id: guid,
    status,
    tags,
    message: typeof text === 'string' ? text : '',
    updatedAt: normalizeSentAt(conversation?.updatedAt || conversation?.lastMessage?.sentAt),
    unreadMessageCount,
    actionUnreadStage,
    influencer: {
      id: influencerId,
      display_name: group?.name,
      image,
    },
    campaign: {
      id: campaignId,
      campaign_name: group?.description,
      slug: meta.slug,
    },
    conversationWith: group,
  };
};

/** Build a list row from a CometChat Group (+ optional inbound message). Used for realtime new chats. */
export const mapGroupToConversation = (
  group: any,
  extras?: {
    message?: string;
    updatedAt?: number;
    inferredStatus?: string | null;
    actionUnreadStage?: string | null;
    unreadMessageCount?: number;
  }
): MappedConversation | null => {
  if (!group) return null;
  const guid = String(group?.guid || group?.getGuid?.() || '').replace(/^group_/, '');
  if (!guid) return null;

  const rawMeta = typeof group.getMetadata === 'function' ? group.getMetadata() : group?.metadata;
  const meta = rawMeta && typeof rawMeta === 'object' ? rawMeta : {};
  const tags = asStringArray(
    typeof group.getTags === 'function' ? group.getTags() : group?.tags
  );
  const status =
    extras?.inferredStatus ||
    statusFromTags(tags) ||
    statusFromTags(meta?.status ? [String(meta.status)] : []) ||
    '';

  const name = (typeof group.getName === 'function' ? group.getName() : group?.name) || '';
  const description =
    (typeof group.getDescription === 'function' ? group.getDescription() : group?.description) ||
    '';
  const rawIcon = (typeof group.getIcon === 'function' ? group.getIcon() : group?.icon) || '';
  const image = isPlaceholderImage(rawIcon) ? undefined : rawIcon;

  let nextTags = tags;
  if (status && !tags.includes(status)) {
    const cleaned = tags.filter((t) => !(ALL_STAGE_KEYS as readonly string[]).includes(t));
    nextTags = [...cleaned, status];
  }

  return {
    id: guid,
    status,
    tags: nextTags,
    message: extras?.message || '',
    updatedAt:
      extras?.updatedAt || normalizeSentAt(group?.updatedAt) || Math.floor(Date.now() / 1000),
    unreadMessageCount: Number(extras?.unreadMessageCount || 0),
    actionUnreadStage: extras?.actionUnreadStage ?? null,
    influencer: {
      id: meta?.influencer?.id,
      display_name: name,
      image,
    },
    campaign: {
      id: meta?.campaign_id || campaignIdFromTags(nextTags),
      campaign_name: description,
      slug: meta?.slug,
    },
    conversationWith: group,
  };
};

/**
 * Fetch conversations once via ChatCustomFetch.
 * Filter + search + pagination happen locally afterwards.
 */

export const fetchAllConversationsOnce = async (userId?: string | number) => {

  const params: any = {
    conversationType: 'group',
    perPage: CONVERSATIONS_API_LIMIT,
    page: 1,
    withUserAndGroupTags: true,
  }

  if (process.env.NEXT_PUBLIC_APP_ENV === 'production') {
    params.groupTags = ['quotation_available', 'drafting_deliverables', 'draft_available', 'posting_deliverables', 'completion_request', 'closed', 'waiting_for_quotations'];
  }

  const res = await ChatCustomFetch(
    {
      url: ChatConversations,
      params: params,
      headers: userId ? { onBehalfOf: String(userId) } : undefined,
    },
    null,
    false
  );

  const payload = res?.data;
  const list = Array.isArray(payload?.data) ? payload.data : [];

  const items = list
    .map((c: any) => mapCometConversation(c))
    .filter(Boolean) as MappedConversation[];

  items.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));

  return {
    items,
    total: items.length,
  };
};

/** Local filter: status tags + search + campaign id from tags (no API call). */
export const filterConversationsLocally = (
  items: MappedConversation[],
  args: {
    filter: string;
    search?: string;
    campaignId?: string | number | 'all' | null;
    unreadCounts?: Record<string, number>;
  }
): MappedConversation[] => {
  const { filter, search, campaignId, unreadCounts = {} } = args;
  let list = [...items];

  if (campaignId && campaignId !== 'all') {
    list = list.filter((item) => matchesCampaign(item, campaignId));
  }

  if (filter === 'working') {
    list = list.filter((item) => (WORKING_STAGES as readonly string[]).includes(item.status));
  } else if (filter === 'unread') {
    // Message unread in eligible stages; exclude unread drafts + pending quotations
    list = list.filter((item) => conversationCountsTowardUnreadFilter(item, unreadCounts));
  } else if (filter !== 'all') {
    // Stage filters: every conversation currently in that stage
    const tags = getTagsForFilter(filter);
    if (tags?.length === 1) {
      list = list.filter((item) => item.status === tags[0] || item.tags?.includes(tags[0]));
    } else if (tags?.length) {
      list = list.filter(
        (item) => tags.includes(item.status) || tags.some((t) => item.tags?.includes(t))
      );
    }
  }

  if (search?.trim()) {
    const q = search.trim().toLowerCase();
    list = list.filter((item) => {
      const name = item?.influencer?.display_name?.toLowerCase() || '';
      const msg = item?.message?.toLowerCase() || '';
      const campaign = item?.campaign?.campaign_name?.toLowerCase() || '';
      return name.includes(q) || msg.includes(q) || campaign.includes(q);
    });
  }

  list.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
  return list;
};

/**
 * Prefer IDs already on the mapped conversation (metadata + tags).
 * Fall back to CometChat group members only if still missing.
 */
export const resolveConversationIds = async (
  item: MappedConversation,
  options?: {
    fallbackCampaignId?: string | number;
    brandUserId?: string | number;
  }
) => {
  let influencerId =
    item?.influencer?.id != null ? String(item.influencer.id) : undefined;
  let campaignId =
    item?.campaign?.id != null
      ? String(item.campaign.id)
      : options?.fallbackCampaignId && options.fallbackCampaignId !== 'all'
        ? String(options.fallbackCampaignId)
        : campaignIdFromTags(item.tags || []);

  if (influencerId && campaignId) {
    return { influencerId, campaignId };
  }

  const brandUserId = options?.brandUserId != null ? String(options.brandUserId) : undefined;
  const guid = item.id;

  try {
    const membersRequest = new CometChat.GroupMembersRequestBuilder(guid)
      .setLimit(100)
      .build();
    const members = (await membersRequest.fetchNext()) || [];
    const others: Array<{ uid: string; scope: string }> = [];

    members.forEach((m: any) => {
      const uid = String(
        (typeof m.getUid === 'function' ? m.getUid() : m?.uid) || m?.user?.uid || ''
      );
      if (!uid) return;
      const scope = String(
        (typeof m.getScope === 'function' ? m.getScope() : m?.scope) || ''
      ).toLowerCase();
      if (scope === 'moderator' && !campaignId) {
        campaignId = uid;
        return;
      }
      if (brandUserId && uid === brandUserId) return;
      others.push({ uid, scope });
    });

    if (!influencerId) {
      influencerId =
        others.find((m) => m.scope === 'participant')?.uid || others[0]?.uid;
    }
  } catch {
    // ignore
  }

  if (!influencerId || !campaignId) {
    try {
      const group = await CometChat.getGroup(guid);
      const meta =
        (typeof (group as any)?.getMetadata === 'function'
          ? (group as any).getMetadata()
          : (group as any)?.metadata) || {};
      if (!influencerId && (meta?.influencer?.id)) {
        influencerId = String(meta.influencer?.id);
      }
      if (!campaignId && (meta.campaign_id || meta.campaignId)) {
        campaignId = String(meta.campaign_id || meta.campaignId);
      }
    } catch {
      // ignore
    }
  }

  return { influencerId, campaignId };
};
