import { Injectable, Logger } from '@nestjs/common';

export interface TgSendMessageOptions {
  chat_id: string | number;
  text: string;
  parse_mode?: 'HTML' | 'Markdown' | 'MarkdownV2';
  reply_markup?: Record<string, unknown>;
}

export interface TgBotInfo {
  id: number;
  is_bot: boolean;
  first_name: string;
  username: string;
}

export interface TgUpdate {
  update_id: number;
  message?: TgMessage;
  callback_query?: TgCallbackQuery;
}

export interface TgMessage {
  message_id: number;
  from?: TgUser;
  chat: TgChat;
  date: number;
  text?: string;
  contact?: TgContact;
}

export interface TgCallbackQuery {
  id: string;
  from: TgUser;
  message?: TgMessage;
  data?: string;
}

export interface TgUser {
  id: number;
  is_bot: boolean;
  first_name: string;
  last_name?: string;
  username?: string;
  language_code?: string;
}

export interface TgChat {
  id: number;
  type: string;
  first_name?: string;
  last_name?: string;
  username?: string;
}

export interface TgContact {
  phone_number: string;
  first_name: string;
  last_name?: string;
  user_id?: number;
}

@Injectable()
export class TelegramApiService {
  private readonly logger = new Logger(TelegramApiService.name);
  private readonly baseUrl = 'https://api.telegram.org';

  private url(token: string, method: string): string {
    return `${this.baseUrl}/bot${token}/${method}`;
  }

  private async call<T>(token: string, method: string, body?: Record<string, unknown>): Promise<T> {
    const res = await fetch(this.url(token, method), {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: body ? JSON.stringify(body) : undefined,
      signal: AbortSignal.timeout(15000),
    });

    const json = (await res.json()) as { ok: boolean; result: T; description?: string };

    if (!json.ok) {
      this.logger.error(`Telegram API error: ${method} — ${json.description}`);
      throw new Error(`Telegram API: ${json.description}`);
    }

    return json.result;
  }

  async getMe(token: string): Promise<TgBotInfo> {
    return this.call<TgBotInfo>(token, 'getMe');
  }

  async setWebhook(token: string, url: string): Promise<boolean> {
    return this.call<boolean>(token, 'setWebhook', {
      url,
      allowed_updates: ['message', 'callback_query'],
      drop_pending_updates: true,
    });
  }

  async deleteWebhook(token: string): Promise<boolean> {
    return this.call<boolean>(token, 'deleteWebhook', { drop_pending_updates: true });
  }

  async sendMessage(token: string, options: TgSendMessageOptions): Promise<TgMessage> {
    return this.call<TgMessage>(
      token,
      'sendMessage',
      options as unknown as Record<string, unknown>,
    );
  }

  async answerCallbackQuery(
    token: string,
    callbackQueryId: string,
    text?: string,
  ): Promise<boolean> {
    return this.call<boolean>(token, 'answerCallbackQuery', {
      callback_query_id: callbackQueryId,
      text,
    });
  }

  buildInlineKeyboard(
    buttons: Array<{ text: string; callback_data?: string; url?: string }>,
  ): Record<string, unknown> {
    return {
      inline_keyboard: buttons.map((b) => [b]),
    };
  }

  buildReplyKeyboard(
    buttons: Array<{ text: string; request_contact?: boolean }>,
    options?: { one_time_keyboard?: boolean; resize_keyboard?: boolean },
  ): Record<string, unknown> {
    return {
      keyboard: buttons.map((b) => [b]),
      one_time_keyboard: options?.one_time_keyboard ?? true,
      resize_keyboard: options?.resize_keyboard ?? true,
    };
  }

  removeKeyboard(): Record<string, unknown> {
    return { remove_keyboard: true };
  }
}
