/**
 * ZCLAW Feishu Channel Plugin
 * 
 * Registers Feishu (飞书/Lark) as a messaging channel for OpenClaw Gateway.
 * Supports:
 * - Receiving messages via Feishu Event Subscription
 * - Sending text/rich messages back to Feishu
 * - OAuth token management (tenant_access_token)
 * - Webhook-based event handling
 */

interface PluginAPI {
  config: Record<string, any>;
  registerChannel(opts: { plugin: ChannelPlugin }): void;
  registerHook(event: string, handler: (...args: any[]) => any, meta?: Record<string, any>): void;
  registerGatewayMethod(method: string, handler: (ctx: any) => void): void;
  registerService(id: string, service: BackgroundService): void;
}

interface BackgroundService {
  start(): Promise<void>;
  stop(): Promise<void>;
}

interface ChannelPlugin {
  id: string;
  meta: {
    id: string;
    label: string;
    selectionLabel: string;
    docsPath?: string;
    blurb: string;
    aliases: string[];
    detailLabel?: string;
  };
  capabilities: {
    chatTypes: string[];
  };
  config: {
    listAccountIds: (cfg: any) => string[];
    resolveAccount: (cfg: any, accountId?: string) => any;
  };
  outbound: {
    deliveryMode: string;
    sendText: (opts: SendTextOpts) => Promise<{ ok: boolean; error?: string }>;
    sendRichText?: (opts: SendRichTextOpts) => Promise<{ ok: boolean; error?: string }>;
  };
  gateway?: {
    start?: (ctx: any) => Promise<void>;
    stop?: (ctx: any) => Promise<void>;
  };
}

interface SendTextOpts {
  text: string;
  chatId: string;
  accountId?: string;
}

interface SendRichTextOpts {
  content: any;
  chatId: string;
  accountId?: string;
}

// Feishu API helpers
class FeishuClient {
  private baseUrl = 'https://open.feishu.cn/open-apis';
  private appId: string;
  private appSecret: string;
  private tenantToken: string | null = null;
  private tokenExpiry: number = 0;

  constructor(appId: string, appSecret: string) {
    this.appId = appId;
    this.appSecret = appSecret;
  }

  async getTenantToken(): Promise<string> {
    if (this.tenantToken && Date.now() < this.tokenExpiry) {
      return this.tenantToken;
    }

    const response = await fetch(`${this.baseUrl}/auth/v3/tenant_access_token/internal`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        app_id: this.appId,
        app_secret: this.appSecret,
      }),
    });

    const data: any = await response.json();
    if (data.code !== 0) {
      throw new Error(`Feishu auth failed: ${data.msg}`);
    }

    this.tenantToken = data.tenant_access_token;
    // Token valid for 2 hours, refresh at 1.5h
    this.tokenExpiry = Date.now() + 90 * 60 * 1000;
    return this.tenantToken!;
  }

  async sendMessage(chatId: string, msgType: string, content: any): Promise<{ ok: boolean; error?: string }> {
    try {
      const token = await this.getTenantToken();
      const response = await fetch(`${this.baseUrl}/im/v1/messages?receive_id_type=chat_id`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          receive_id: chatId,
          msg_type: msgType,
          content: JSON.stringify(content),
        }),
      });

      const data: any = await response.json();
      if (data.code !== 0) {
        return { ok: false, error: data.msg };
      }
      return { ok: true };
    } catch (error: any) {
      return { ok: false, error: error.message };
    }
  }

  async sendText(chatId: string, text: string): Promise<{ ok: boolean; error?: string }> {
    return this.sendMessage(chatId, 'text', { text });
  }

  async sendRichText(chatId: string, content: any): Promise<{ ok: boolean; error?: string }> {
    return this.sendMessage(chatId, 'post', content);
  }
}

// Global client instance per account
const clients = new Map<string, FeishuClient>();

function getClient(account: { appId: string; appSecret: string }, accountId: string): FeishuClient {
  if (!clients.has(accountId)) {
    clients.set(accountId, new FeishuClient(account.appId, account.appSecret));
  }
  return clients.get(accountId)!;
}

// Channel definition
const feishuChannel: ChannelPlugin = {
  id: 'feishu',
  meta: {
    id: 'feishu',
    label: '飞书 (Feishu)',
    selectionLabel: 'Feishu / Lark',
    blurb: 'Connect to Feishu (飞书) for messaging via Feishu Bot API.',
    aliases: ['lark', 'feishu'],
    detailLabel: '飞书机器人',
  },
  capabilities: {
    chatTypes: ['direct', 'group'],
  },
  config: {
    listAccountIds: (cfg: any) =>
      Object.keys(cfg.channels?.feishu?.accounts ?? {}),
    resolveAccount: (cfg: any, accountId?: string) =>
      cfg.channels?.feishu?.accounts?.[accountId ?? 'default'] ?? { accountId },
  },
  outbound: {
    deliveryMode: 'direct',
    sendText: async ({ text, chatId, accountId }: SendTextOpts) => {
      const cfg = (globalThis as any).__openclaw_config;
      const account = feishuChannel.config.resolveAccount(cfg, accountId);
      if (!account?.appId || !account?.appSecret) {
        return { ok: false, error: 'Feishu account not configured (missing appId/appSecret)' };
      }
      const client = getClient(account, accountId ?? 'default');
      return client.sendText(chatId, text);
    },
    sendRichText: async ({ content, chatId, accountId }: SendRichTextOpts) => {
      const cfg = (globalThis as any).__openclaw_config;
      const account = feishuChannel.config.resolveAccount(cfg, accountId);
      if (!account?.appId || !account?.appSecret) {
        return { ok: false, error: 'Feishu account not configured' };
      }
      const client = getClient(account, accountId ?? 'default');
      return client.sendRichText(chatId, content);
    },
  },
};

/**
 * Plugin entry point
 */
export default function register(api: PluginAPI) {
  // Register Feishu as a channel
  api.registerChannel({ plugin: feishuChannel });

  // Register custom RPC method for Feishu status
  api.registerGatewayMethod('feishu.status', ({ respond }: any) => {
    const accountIds = feishuChannel.config.listAccountIds(api.config);
    respond(true, {
      channel: 'feishu',
      accounts: accountIds.length,
      configured: accountIds.length > 0,
    });
  });

  // Startup hook
  api.registerHook('gateway:startup', async () => {
    const accountIds = feishuChannel.config.listAccountIds(api.config);
    if (accountIds.length > 0) {
      console.log(`[ZCLAW] Feishu channel registered with ${accountIds.length} account(s)`);
      // Pre-warm token for each account
      for (const id of accountIds) {
        try {
          const account = feishuChannel.config.resolveAccount(api.config, id);
          if (account?.appId && account?.appSecret && account?.enabled !== false) {
            const client = getClient(account, id);
            await client.getTenantToken();
            console.log(`[ZCLAW] Feishu account "${id}" token acquired`);
          }
        } catch (err: any) {
          console.warn(`[ZCLAW] Feishu account "${id}" token failed: ${err.message}`);
        }
      }
    } else {
      console.log('[ZCLAW] Feishu channel registered (no accounts configured yet)');
    }
  }, { name: 'zclaw-feishu.startup', description: 'Initialize Feishu connections on startup' });
}
