import express from 'express';
import cors from 'cors';
import multer from 'multer';
import dotenv from 'dotenv';
import { BskyAgent } from '@atproto/api';
import { OAuth2Authenticator, Client } from 'mixi2-js';
import sharp from 'sharp';

dotenv.config();

const app = express();
const port = 3000;

app.use(cors());
app.use(express.json());
const upload = multer({ storage: multer.memoryStorage() });

// 🦋 Blueskyへの投稿処理
async function postToBluesky(text, imageBuffer, mimeType) {
  console.log("Blueskyへの投稿を開始します...");
  try {
    const agent = new BskyAgent({ service: '<https://bsky.social>' });
    await agent.login({
      identifier: process.env.BLUESKY_HANDLE,
      password: process.env.BLUESKY_APP_PASSWORD,
    });

    let embed = undefined;
    if (imageBuffer && mimeType) {
      const uploadRes = await agent.uploadBlob(imageBuffer, { encoding: mimeType });
      embed = {
        $type: 'app.bsky.embed.images',
        images: [{ image: uploadRes.data.blob, alt: 'Uploaded via local bot' }]
      };
    }

    await agent.post({
      text: text || '',
      createdAt: new Date().toISOString(),
      embed: embed
    });
    console.log("✅ Blueskyへの投稿に成功しました。");
  } catch (error) {
    console.error("❌ Blueskyへの投稿に失敗しました:", error.message);
  }
}

// 🟠 mixi2への投稿処理 (Step3 スキップ強行突破版)
async function postToMixi2(text, imageBuffer, mimeType) {
  console.log("mixi2への投稿を開始します...");
  try {
    const authenticator = new OAuth2Authenticator({
      clientId: process.env.MIXI2_CLIENT_ID,
      clientSecret: process.env.MIXI2_CLIENT_SECRET,
      tokenUrl: '<https://application-auth.mixi.social/oauth2/token>'
    });

    const client = new Client({
      apiAddress: 'application-api.mixi.social:443',
      authenticator: authenticator
    });

    let mediaIdList = [];

    if (imageBuffer && mimeType) {
      console.log("mixi2: [Step 1] メディアアップロードの開始...");
      const initRes = await client.initiatePostMediaUpload({
        mediaType: 'TYPE_IMAGE',
        contentType: mimeType,
        dataSize: imageBuffer.length
      });
      
      const mediaId = initRes.mediaId || initRes.media_id;
      const uploadUrl = initRes.uploadUrl || initRes.upload_url;

      if (!mediaId || !uploadUrl) throw new Error("ID取得失敗");

      console.log(`mixi2: [Step 2] バイナリデータの確実な送信...`);
      
      let accessToken;
      if (typeof authenticator.getAccessToken === 'function') {
        accessToken = await authenticator.getAccessToken();
      } else {
        const tokenRes = await fetch('<https://application-auth.mixi.social/oauth2/token>', {
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          body: `grant_type=client_credentials&client_id=${process.env.MIXI2_CLIENT_ID}&client_secret=${process.env.MIXI2_CLIENT_SECRET}`
        });
        const tokenData = await tokenRes.json();
        accessToken = tokenData.access_token;
      }

      // Bufferをそのまま送信
      const uploadRes = await fetch(uploadUrl, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/octet-stream',
          'Content-Length': imageBuffer.length.toString()
        },
        body: imageBuffer 
      });

      console.log(`👉 Step 2 応答: HTTP ${uploadRes.status}`);
      if (!uploadRes.ok) throw new Error(`Upload API Error: ${uploadRes.status}`);

      console.log("mixi2: [Step 3] ライブラリのバグを回避するため、ポーリングをスキップして8秒待機します...");
      // ⚠️ 諸悪の根源である状況確認機能を使わず、処理が終わるのを強制的に待つ
      await new Promise(resolve => setTimeout(resolve, 8000));
      
      mediaIdList.push(mediaId);
    }

    console.log("mixi2: [Step 4] ポストの作成...");
    await client.createPost({
      text: text || '',
      mediaIdList: mediaIdList.length > 0 ? mediaIdList : undefined
    });
    console.log("✅ mixi2への投稿に成功しました。");
  } catch (error) {
    console.error("❌ mixi2への投稿に失敗しました:", error.message || error);
  }
}

// 🥝 Misskeyへの投稿処理
async function postToMisskey(text, imageBuffer, mimeType, originalName) {
  console.log("Misskeyへの投稿を開始します...");
  try {
    const host = process.env.MISSKEY_HOST || '<https://misskey.io>';
    let fileIds = [];
    if (imageBuffer && mimeType) {
      const blob = new Blob([imageBuffer], { type: mimeType });
      const formData = new FormData();
      formData.append('i', process.env.MISSKEY_TOKEN);
      formData.append('file', blob, originalName || 'image.jpg');

      const uploadRes = await fetch(`${host}/api/drive/files/create`, { method: 'POST', body: formData });
      if (!uploadRes.ok) throw new Error("Upload failed");
      const uploadData = await uploadRes.json();
      fileIds.push(uploadData.id);
    }

    const response = await fetch(`${host}/api/notes/create`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        i: process.env.MISSKEY_TOKEN,
        text: text || null,
        fileIds: fileIds.length > 0 ? fileIds : undefined
      })
    });
    if (!response.ok) throw new Error("Post failed");
    console.log("✅ Misskeyへの投稿に成功しました。");
  } catch (error) {
    console.error("❌ Misskeyへの投稿に失敗しました:", error.message);
  }
}

// 🚪 APIエンドポイント
app.post('/post', upload.single('image'), async (req, res) => {
  const text = req.body.text;
  const image = req.file;

  if (!text && !image) return res.status(400).json({ error: "テキストまたは画像が必要です。" });

  console.log(`\n=== 新しい投稿リクエストを受信しました ===`);
  if (text) console.log(`テキスト: ${text}`);
  
  let finalBuffer = null;
  let finalMimeType = null;
  let originalName = null;

  if (image) {
    originalName = image.originalname;
    finalBuffer = image.buffer;
    finalMimeType = image.mimetype;

    if (image.buffer.length > 1900000) {
      console.log("⚠️ 画像サイズが大きいため、共通の最適化(リサイズ&圧縮)を行います...");
      finalBuffer = await sharp(image.buffer)
        .resize({ width: 1600, withoutEnlargement: true }) // 縦横サイズも縮小
        .jpeg({ quality: 80 })
        .toBuffer();
      finalMimeType = 'image/jpeg';
      console.log(`✅ 最適化完了: ${finalBuffer.length} bytes に軽量化しました。`);
    }
  }

  res.status(200).json({ message: "投稿処理を開始しました。" });

  await Promise.all([
    postToBluesky(text, finalBuffer, finalMimeType),
    postToMixi2(text, finalBuffer, finalMimeType),
    postToMisskey(text, finalBuffer, finalMimeType, originalName)
  ]);

  console.log("=== 全ての投稿処理が完了しました ===\n");
});

app.listen(port, () => {
  console.log(`マルチSNS投稿サーバーが起動しました!`);
  console.log(`待機ポート: ${port}`);
});