/**
 * سرویس ارتباطات سازمانی.
 *
 * معماری:
 *   CommunicationService
 *     ├── TelegramAdapter
 *     └── EitaaAdapter
 *
 * قاعده‌ی قطعی: هیچ توکنی سمت کلاینت نمی‌رود و هیچ «تحویل موفق» جعلی ثبت نمی‌شود.
 * اگر اعتبارنامه‌ی سرویس تنظیم نشده باشد، پیام با وضعیت `unavailable` ذخیره می‌شود
 * و فقط یک Deep Link معتبر برای اقدام دستی تولید می‌گردد.
 */
import { eq } from 'drizzle-orm';
import { getDb } from '../../database/client.js';
import { communicationChannels, outboundMessages } from '../../database/schema/index.js';
import { config } from '../../config/index.js';
import { Errors } from '../../common/errors.js';

export type OutboundPayload = { text: string; attachments?: string[]; caseId?: string };

export type DeliveryResult = {
  state: 'delivered' | 'failed' | 'unavailable';
  deepLink?: string;
  error?: string;
  providerMessageId?: string;
};

export interface ChannelAdapter {
  readonly provider: string;
  isConfigured(): boolean;
  buildDeepLink(handle: string, payload: OutboundPayload): string;
  send(handle: string, payload: OutboundPayload): Promise<DeliveryResult>;
}

class TelegramAdapter implements ChannelAdapter {
  readonly provider = 'telegram';

  isConfigured() {
    return Boolean(config.communications.telegramBotToken);
  }

  buildDeepLink(handle: string, payload: OutboundPayload) {
    const username = handle.replace(/^@/, '');
    return `https://t.me/${encodeURIComponent(username)}?text=${encodeURIComponent(payload.text.slice(0, 900))}`;
  }

  async send(handle: string, payload: OutboundPayload): Promise<DeliveryResult> {
    if (!this.isConfigured()) {
      return { state: 'unavailable', deepLink: this.buildDeepLink(handle, payload), error: 'TELEGRAM_BOT_TOKEN تنظیم نشده است.' };
    }
    try {
      const res = await fetch(`https://api.telegram.org/bot${config.communications.telegramBotToken}/sendMessage`, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ chat_id: handle, text: payload.text }),
      });
      const data = (await res.json()) as { ok?: boolean; result?: { message_id?: number }; description?: string };
      if (!res.ok || !data.ok) return { state: 'failed', error: data.description ?? `HTTP ${res.status}` };
      return { state: 'delivered', providerMessageId: String(data.result?.message_id ?? '') };
    } catch (error) {
      return { state: 'failed', error: (error as Error).message };
    }
  }
}

class EitaaAdapter implements ChannelAdapter {
  readonly provider = 'eitaa';

  isConfigured() {
    return Boolean(config.communications.eitaaToken);
  }

  buildDeepLink(handle: string) {
    return `https://eitaa.com/${encodeURIComponent(handle.replace(/^@/, ''))}`;
  }

  async send(handle: string, payload: OutboundPayload): Promise<DeliveryResult> {
    if (!this.isConfigured()) {
      return { state: 'unavailable', deepLink: this.buildDeepLink(handle), error: 'EITAA_TOKEN تنظیم نشده است.' };
    }
    try {
      const res = await fetch(`https://eitaayar.ir/api/${config.communications.eitaaToken}/sendMessage`, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ chat_id: handle, text: payload.text }),
      });
      if (!res.ok) return { state: 'failed', error: `HTTP ${res.status}` };
      return { state: 'delivered' };
    } catch (error) {
      return { state: 'failed', error: (error as Error).message };
    }
  }
}

const adapters: Record<string, ChannelAdapter> = {
  telegram: new TelegramAdapter(),
  eitaa: new EitaaAdapter(),
};

export function adapterStatus() {
  return Object.values(adapters).map((a) => ({ provider: a.provider, configured: a.isConfigured() }));
}

/** پیام را در صف قرار می‌دهد و بلافاصله یک بار تلاش ارسال می‌کند */
export async function enqueueOutbound(channelId: string, payload: OutboundPayload, actorId?: string) {
  const db = getDb();
  const [channel] = await db.select().from(communicationChannels).where(eq(communicationChannels.id, channelId));
  if (!channel || !channel.isActive) throw Errors.notFound('کانال ارتباطی فعالی با این شناسه یافت نشد.');
  const adapter = adapters[channel.provider];
  if (!adapter) throw Errors.validation(`آداپتور «${channel.provider}» پشتیبانی نمی‌شود.`);

  const [row] = await db.insert(outboundMessages).values({
    channelId, provider: channel.provider, payload: payload as unknown as Record<string, unknown>,
    state: 'queued', createdBy: actorId ?? null,
    deepLink: adapter.buildDeepLink(channel.handle, payload),
  }).returning();

  const result = await adapter.send(channel.handle, payload);
  const [updated] = await db.update(outboundMessages).set({
    state: result.state,
    attempts: row.attempts + 1,
    lastError: result.error ?? null,
    deepLink: result.deepLink ?? row.deepLink,
    updatedAt: new Date(),
  }).where(eq(outboundMessages.id, row.id)).returning();

  return updated;
}

/** تلاش مجدد برای پیام‌های ناموفق (توسط زمان‌بند) */
export async function retryFailed(limit = 20) {
  const db = getDb();
  const rows = await db.select().from(outboundMessages).where(eq(outboundMessages.state, 'failed')).limit(limit);
  let retried = 0;
  for (const row of rows) {
    if (row.attempts >= 5) continue;
    const [channel] = await db.select().from(communicationChannels).where(eq(communicationChannels.id, row.channelId));
    const adapter = channel ? adapters[channel.provider] : undefined;
    if (!channel || !adapter) continue;
    const result = await adapter.send(channel.handle, row.payload as unknown as OutboundPayload);
    await db.update(outboundMessages).set({
      state: result.state, attempts: row.attempts + 1, lastError: result.error ?? null, updatedAt: new Date(),
    }).where(eq(outboundMessages.id, row.id));
    retried++;
  }
  return { retried };
}
