import { ApplicationFunction, Probot } from 'probot';
import metadata from 'probot-metadata';
import { TailchatClient } from './client';
import {
  configPath,
  generateErrorBlock,
  generateTopicCommentCreateContent,
  generateTopicCreateContent,
} from './utils';
import bodyParser from 'body-parser';
import _ from 'lodash';
import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
dotenv.config();

const LABEL = 'tailchat-topic';
const TOPIC_KEY = 'tailchatTopicId';

if (
  !process.env.TAILCHAT_API_URL ||
  !process.env.TAILCHAT_APP_ID ||
  !process.env.TAILCHAT_APP_SECRET
) {
  throw new Error(
    'Require env: TAILCHAT_API_URL, TAILCHAT_APP_ID, TAILCHAT_APP_SECRET'
  );
}

const defaultTailchatApiUrl = process.env.TAILCHAT_API_URL;
const tailchatAppId = process.env.TAILCHAT_APP_ID;
const tailchatAppSecret = process.env.TAILCHAT_APP_SECRET;
const tailchatWebUrl =
  process.env.TAILCHAT_WEB_URL || process.env.TAILCHAT_API_URL;

export const appFn: ApplicationFunction = (app, { getRouter }) => {
  app.on('issues.opened', async (ctx) => {
    if (ctx.isBot) {
      return;
    }

    try {
      const { data } = await ctx.octokit.repos.getContent(
        ctx.repo({
          path: configPath,
        })
      );

      if (!(!Array.isArray(data) && 'content' in data)) {
        throw new Error('config file type error');
      }

      // 是配置文件

      const { tailchatClient, groupId, panelId } =
        createTailchatContextWithConfig(data.content);

      console.log('配置信息', { tailchatClient, groupId, panelId });

      // 发送到tailchat
      const { data: topic } = await tailchatClient.call(
        'plugin:com.msgbyte.topic.create',
        {
          groupId,
          panelId,
          content: generateTopicCreateContent(
            ctx.payload.issue.user.login,
            ctx.payload.issue.title,
            ctx.payload.issue.body ?? '',
            ctx.payload.issue.html_url
          ),
          meta: {
            tailchatHost: tailchatClient.url,
            installationId: ctx.payload.installation?.id,
            githubRepoOwner: ctx.payload.repository.owner.login,
            githubRepoName: ctx.payload.repository.name,
            githubIssueNumber: ctx.payload.issue.number,
          },
        }
      );

      console.log('Tailchat Topic 创建成功', topic);

      await Promise.all([
        ctx.octokit.issues.createComment(
          ctx.issue({
            body: `Thanks for opening this issue! Tailchat topic is created in ${tailchatWebUrl}/main/group/${groupId}/${panelId}!`,
          })
        ),
        ctx.octokit.issues.addLabels(
          ctx.repo({
            issue_number: ctx.payload.issue.number,
            labels: [LABEL],
          })
        ),
        metadata(ctx).set(TOPIC_KEY, topic._id),
      ]);

      console.log('发送相关信息到 Github 完毕');
    } catch (err) {
      console.error(err);

      await ctx.octokit.issues.createComment(
        ctx.issue({
          body: generateErrorBlock(err),
        })
      );
    }
  });

  app.on('issue_comment.created', async (ctx) => {
    if (ctx.isBot) {
      console.error('This comment created by Bot, Skip!');
      return;
    }
    // 发送到tailchat

    try {
      const topicId = await metadata(ctx).get(TOPIC_KEY);
      if (!topicId) {
        console.error('Not found topic id, Skip!');
        return;
      }

      const { data } = await ctx.octokit.repos.getContent(
        ctx.repo({
          path: configPath,
        })
      );

      if (!(!Array.isArray(data) && 'content' in data)) {
        throw new Error('Config file type error');
      }

      // 是配置文件

      const { tailchatClient, groupId, panelId } =
        createTailchatContextWithConfig(data.content);

      // 发送到tailchat
      await tailchatClient.call('plugin:com.msgbyte.topic.createComment', {
        groupId,
        panelId,
        topicId,
        content: generateTopicCommentCreateContent(
          ctx.payload.comment.user.login,
          ctx.payload.comment.body ?? '',
          ctx.payload.comment.html_url
        ),
      });
    } catch (err) {
      console.error(err);

      await ctx.octokit.issues.createComment(
        ctx.issue({
          body: generateErrorBlock(err),
        })
      );
    }
  });

  // app.on('installation.created', async (ctx) => {
  //   const installationId = ctx.payload.installation.id;
  //   const installationTargetName = ctx.payload.installation.account.login;
  //   const installationTargetRepositories = ctx.payload.repositories;

  //   console.log('installation.created', {
  //     installationId,
  //     installationTargetName,
  //     installationTargetRepositories,
  //   });
  // });

  buildRouter(app, getRouter);
};

/**
 * 从配置文件中创建上下文
 *
 * 因为考虑serverless服务因此不能全局管理
 */
function createTailchatContextWithConfig(githubRaw: string) {
  const content = Buffer.from(githubRaw, 'base64').toString();
  const json = JSON.parse(content);
  const tailchatHost = json['tailchatHost'] ?? defaultTailchatApiUrl;
  const groupId = json['groupId'];
  const panelId = json['panelId'];

  if (!groupId || !panelId) {
    throw new Error('config format error');
  }

  const tailchatClient = createTailchatClient(tailchatHost);

  return {
    tailchatClient,
    groupId,
    panelId,
  };
}

function createTailchatClient(tailchatHost = defaultTailchatApiUrl) {
  const tailchatClient = new TailchatClient(
    tailchatHost,
    tailchatAppId,
    tailchatAppSecret
  );

  return tailchatClient;
}

export function buildRouter(
  app: Probot,
  getRouter: Parameters<ApplicationFunction>[1]['getRouter']
) {
  if (getRouter) {
    getRouter('/')
      .get('/api', (_req, res) => {
        res.send('Hello World! Github app api server is working!');
      })
      .get('/api/message/webhook', (_req, res) => {
        res.send('Please use POST method');
      })
      .post('/api/message/webhook', bodyParser.json(), (req, res) => {
        (async () => {
          try {
            // 根据收件箱内容向 Github Issue 创建话题
            const inboxItem = req.body ?? {};
            if (inboxItem.type !== 'plugin:com.msgbyte.topic.comment') {
              // 如果不是回复消息，则跳过
              return;
            }

            const newComment: any =
              _.last(_.get(inboxItem, ['payload', 'comments'])) ?? {};
            const meta = _.get(inboxItem, ['payload', 'meta']) ?? {};
            if (
              !meta.installationId ||
              !meta.githubRepoOwner ||
              !meta.githubRepoName ||
              !meta.githubIssueNumber
            ) {
              console.warn('Cannot pass meta info check:', { meta });
              return;
            }
            if (!newComment.author || !newComment.content) {
              console.warn(
                'Cannot get "newComment.author" or "newComment.content"'
              );
              return;
            }

            // 发送到github comment
            const octokit = await app.auth(Number(meta.installationId));
            const tailchatClient = createTailchatClient(meta.tailchatHost);
            const userInfo = await tailchatClient.call('user.getUserInfo', {
              userId: newComment.author,
            });

            const payload = {
              owner: meta.githubRepoOwner,
              repo: meta.githubRepoName,
              issue_number: meta.githubIssueNumber,
              body: `[${_.get(userInfo, [
                'data',
                'nickname',
              ])}] 在 Tailchat 回复:\n\`\`\`\n${
                newComment.content ?? ''
              }\n\`\`\``,
            };

            console.log('正在向Github Issue创建回复:', payload);

            await octokit.issues.createComment(payload);
          } catch (err) {
            console.error(err);
          }
        })();

        res.send('Success!');
      });
  }
}
