import { Injectable, Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { firstValueFrom } from 'rxjs';
import axios from 'axios';
import * as FormData from 'form-data';
import * as fs from 'fs-extra';
import * as path from 'path';

@Injectable()
export class ZulipService {
  private readonly logger = new Logger(ZulipService.name);

  private readonly zulipUrl: string;
  private readonly botEmail: string;
  private readonly apiKey: string;

  constructor(
    private readonly httpService: HttpService,
    private readonly configService: ConfigService,
  ) {
    this.zulipUrl = this.configService.get<string>('ZULIP_API_URL');
    this.botEmail = this.configService.get<string>('ZULIP_BOT_EMAIL');
    this.apiKey = this.configService.get<string>('ZULIP_API_KEY');
  }

  /**
   * Upload bất kỳ file nào từ external URL lên Zulip
   */
  async uploadBase64ToZulip(base64Data: string): Promise<string> {
    const tempDir = path.join(process.cwd(), 'tmp');
    await fs.ensureDir(tempDir);

    // 1. Lấy thông tin MIME type và phần dữ liệu base64
    let mimeType = 'application/octet-stream';
    let base64Content = base64Data;

    const base64Regex = /^data:(.*?);base64,(.*)$/;
    const match = base64Data.match(base64Regex);
    if (match) {
      mimeType = match[1];
      base64Content = match[2];
    }

    // 2. Lấy phần đuôi file từ MIME type
    const extension = 'jpg';
    const filename = `${Date.now()}-${Math.random().toString(36).substring(7)}.${extension}`;
    const filePath = path.join(tempDir, filename);

    try {
      this.logger.log(`Decoding and saving file from base64...`);

      // 3. Decode Base64 và lưu vào file tạm
      const fileBuffer = Buffer.from(base64Content, 'base64');
      await fs.writeFile(filePath, fileBuffer);

      this.logger.log(`File saved temporarily at: ${filePath}`);

      // 4. Upload file lên Zulip
      const form = new FormData();
      form.append('filename', fs.createReadStream(filePath));

      const uploadRes = await axios.post(
        `${this.zulipUrl}/user_uploads`,
        form,
        {
          auth: {
            username: this.botEmail,
            password: this.apiKey,
          },
          headers: form.getHeaders(),
        },
      );

      const zulipFileUrl = `${uploadRes.data.uri}`;
      this.logger.log(`Uploaded to Zulip: ${zulipFileUrl}`);

      return zulipFileUrl;
    } catch (error) {
      this.logger.error(
        'Upload to Zulip failed',
        error?.response?.data || error.message,
      );
      throw error;
    } finally {
      // 5. Xóa file tạm
      if (await fs.pathExists(filePath)) {
        await fs.remove(filePath);
        this.logger.log(`Deleted temp file: ${filePath}`);
      }
    }
  }

  /**
   * Upload file từ Microsoft Graph share link lên Zulip
   */
  async uploadGraphLinkToZulip({
    url,
    token,
  }: {
    url: string;
    token: string;
  }): Promise<string> {
    const tempDir = path.join(process.cwd(), 'tmp');
    await fs.ensureDir(tempDir);

    let filePath = '';
    try {
      this.logger.log(`Fetching file metadata from Graph API: ${url}`);

      console.log({ token });

      // 1. Gọi Graph API để lấy thông tin file
      const graphRes = await axios.get(url, {
        headers: {
          Authorization: `Bearer ${token.trim()}`, // token lấy từ MS Graph
        },
      });

      const data = graphRes.data;
      const downloadUrl = data['@microsoft.graph.downloadUrl'];
      const fileName = data.name || 'downloaded-file';

      if (!downloadUrl) {
        throw new Error('Cannot find download URL in Graph response.');
      }

      console.log({ downloadUrl });

      this.logger.log(`Direct download URL: ${downloadUrl}`);

      // 2. Tải file từ downloadUrl
      const response = await axios.get(downloadUrl, {
        responseType: 'arraybuffer',
      });
      const extension = path.extname(fileName) || '.bin';
      const tempFileName = `${Date.now()}-${Math.random().toString(36).substring(7)}${extension}`;
      filePath = path.join(tempDir, tempFileName);

      await fs.writeFile(filePath, response.data);
      this.logger.log(`File saved temporarily at: ${filePath}`);

      // 3. Upload file lên Zulip
      const form = new FormData();
      form.append('filename', fs.createReadStream(filePath));

      const uploadRes = await axios.post(
        `${this.zulipUrl}/user_uploads`,
        form,
        {
          auth: {
            username: this.botEmail,
            password: this.apiKey,
          },
          headers: form.getHeaders(),
        },
      );

      const zulipFileUrl = uploadRes.data.uri;
      this.logger.log(`Uploaded to Zulip: ${zulipFileUrl}`);

      return zulipFileUrl;
    } catch (error: any) {
      this.logger.error(
        'Upload to Zulip failed',
        error?.response?.data || error.message,
      );
      throw error;
    } finally {
      // 4. Xóa file tạm
      if (filePath && (await fs.pathExists(filePath))) {
        // await fs.remove(filePath);
        this.logger.log(`Deleted temp file: ${filePath}`);
      }
    }
  }

  /**
   * Gửi tin nhắn vào một topic trong stream
   */
  async sendMessageToTopic(stream: string, topic: string, content: string) {
    const apiUrl = this.zulipUrl + '/messages';

    try {
      const response = await firstValueFrom(
        this.httpService.post(
          apiUrl,
          new URLSearchParams({
            type: 'stream',
            to: stream,
            topic: topic,
            content: content,
          }).toString(),
          {
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            auth: {
              username: this.botEmail,
              password: this.apiKey,
            },
          },
        ),
      );

      this.logger.log(`Message sent to stream "${stream}" topic "${topic}"`);
      return response.data;
    } catch (error) {
      this.logger.error(
        'Failed to send message to Zulip',
        error?.response?.data || error.message,
      );
      throw error;
    }
  }
}
