const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
const { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
const Imap = require('imap');
const simpleParser = require('mailparser').simpleParser;

const IMAP_HOST = process.env.IMAP_HOST || 'xcp.mail.chinaunicom.cn';
const IMAP_PORT = parseInt(process.env.IMAP_PORT || '993', 10);
const IMAP_USER = process.env.IMAP_USER || '';
const IMAP_PASSWORD = process.env.IMAP_PASSWORD || '';

function createImapConnection() {
  return new Imap({
    user: IMAP_USER,
    password: IMAP_PASSWORD,
    host: IMAP_HOST,
    port: IMAP_PORT,
    tls: true,
    tlsOptions: { rejectUnauthorized: false },
  });
}

function connectImap(imap) {
  return new Promise((resolve, reject) => {
    imap.once('ready', () => resolve());
    imap.once('error', (err) => reject(err));
    imap.connect();
  });
}

function openBox(imap, boxName = 'INBOX') {
  return new Promise((resolve, reject) => {
    imap.openBox(boxName, true, (err, box) => {
      if (err) return reject(err);
      resolve(box);
    });
  });
}

function searchMessages(imap, criteria) {
  return new Promise((resolve, reject) => {
    imap.search(criteria, (err, results) => {
      if (err) return reject(err);
      resolve(results || []);
    });
  });
}

function fetchMessageRaw(imap, uid) {
  return new Promise((resolve, reject) => {
    const f = imap.fetch(uid, { bodies: '' });
    let buffer = Buffer.alloc(0);
    f.on('message', (msg) => {
      msg.on('body', (stream) => {
        stream.on('data', (chunk) => {
          buffer = Buffer.concat([buffer, chunk]);
        });
      });
      msg.once('end', () => {});
    });
    f.once('error', reject);
    f.once('end', () => {
      resolve(buffer);
    });
  });
}

async function parseEmail(buffer) {
  const parsed = await simpleParser(buffer);
  return {
    id: parsed.messageId || '',
    subject: parsed.subject || '',
    from: parsed.from ? parsed.from.text : '',
    to: parsed.to ? parsed.to.text : '',
    date: parsed.date ? parsed.date.toISOString() : '',
    body: (parsed.text || '').substring(0, 2000),
  };
}

async function withImap(fn) {
  if (!IMAP_USER || !IMAP_PASSWORD) {
    throw new Error('IMAP_USER 或 IMAP_PASSWORD 未设置。请在 mcp.json 的 env 中填写邮箱账号和客户端授权码。');
  }
  const imap = createImapConnection();
  try {
    await connectImap(imap);
    return await fn(imap);
  } finally {
    try {
      imap.end();
    } catch (e) {}
  }
}

const server = new Server(
  {
    name: 'chinaunicom-email',
    version: '1.0.0',
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: 'list_recent_emails',
        description: '读取收件箱最近 N 封邮件',
        inputSchema: {
          type: 'object',
          properties: {
            folder: {
              type: 'string',
              description: '邮件文件夹名称，默认 INBOX',
              default: 'INBOX',
            },
            limit: {
              type: 'integer',
              description: '返回的最大邮件数量',
              default: 10,
            },
          },
        },
      },
      {
        name: 'search_emails',
        description: '按主题或发件人关键词搜索邮件',
        inputSchema: {
          type: 'object',
          properties: {
            keyword: {
              type: 'string',
              description: '搜索关键词',
            },
            folder: {
              type: 'string',
              description: '邮件文件夹名称，默认 INBOX',
              default: 'INBOX',
            },
            limit: {
              type: 'integer',
              description: '返回的最大邮件数量',
              default: 10,
            },
          },
          required: ['keyword'],
        },
      },
      {
        name: 'read_email',
        description: '根据邮件 ID 读取单封邮件',
        inputSchema: {
          type: 'object',
          properties: {
            message_id: {
              type: 'string',
              description: '邮件 ID',
            },
            folder: {
              type: 'string',
              description: '邮件文件夹名称，默认 INBOX',
              default: 'INBOX',
            },
          },
          required: ['message_id'],
        },
      },
    ],
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    if (name === 'list_recent_emails') {
      const folder = args.folder || 'INBOX';
      const limit = parseInt(args.limit || 10, 10);
      const results = await withImap(async (imap) => {
        await openBox(imap, folder);
        const ids = await searchMessages(imap, ['ALL']);
        const selectedIds = ids.slice(-limit);
        const emails = [];
        for (const id of selectedIds) {
          const raw = await fetchMessageRaw(imap, id);
          const parsed = await parseEmail(raw);
          parsed.id = String(id);
          emails.push(parsed);
        }
        return emails.reverse();
      });
      return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
    }

    if (name === 'search_emails') {
      const keyword = args.keyword || '';
      const folder = args.folder || 'INBOX';
      const limit = parseInt(args.limit || 10, 10);
      const results = await withImap(async (imap) => {
        await openBox(imap, folder);
        const ids = await searchMessages(imap, ['OR', ['SUBJECT', keyword], ['FROM', keyword]]);
        const selectedIds = ids.slice(0, limit);
        const emails = [];
        for (const id of selectedIds) {
          const raw = await fetchMessageRaw(imap, id);
          const parsed = await parseEmail(raw);
          parsed.id = String(id);
          emails.push(parsed);
        }
        return emails;
      });
      return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
    }

    if (name === 'read_email') {
      const messageId = args.message_id;
      const folder = args.folder || 'INBOX';
      const result = await withImap(async (imap) => {
        await openBox(imap, folder);
        const raw = await fetchMessageRaw(imap, messageId);
        const parsed = await parseEmail(raw);
        parsed.id = String(messageId);
        return parsed;
      });
      return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
    }

    return { content: [{ type: 'text', text: `未知工具：${name}` }], isError: true };
  } catch (err) {
    return { content: [{ type: 'text', text: `操作失败：${err.message}` }], isError: true };
  }
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((err) => {
  console.error('Server error:', err);
  process.exit(1);
});
