import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
import { Logger } from '../../utils/logger.js';
import { getIssue as getIssueApi, searchIssues as searchIssuesApi } from '../../utils/jira-resource-api-v2.js';
import { getJiraV2Client } from '../../utils/atlassian-api-base.js';
import { issueSchema, issuesListSchema, transitionsListSchema, commentsListSchema } from '../../schemas/jira.js';
import { standardMetadataSchema } from '../../schemas/common.js';
import { Config, Resources } from '../../utils/mcp-helpers.js';

const logger = Logger.getLogger('JiraResource:Issues');

/**
 * Helper function to get issue details from Jira
 */
async function getIssue(config: any, issueKey: string): Promise<any> {
  return await getIssueApi(config, issueKey);
}

/**
 * Helper function to get a list of issues from Jira (supports pagination)
 */
async function getIssues(config: any, startAt = 0, maxResults = 20, jql = ''): Promise<any> {
  const jqlQuery = jql && jql.trim() ? jql.trim() : '';
  return await searchIssuesApi(config, jqlQuery, maxResults);
}

/**
 * Helper function to search issues by JQL from Jira (supports pagination)
 */
async function searchIssuesByJql(config: any, jql: string, startAt = 0, maxResults = 20): Promise<any> {
  return await searchIssuesApi(config, jql, maxResults);
}

/**
 * Helper function to get a list of transitions for an issue from Jira
 */
async function getIssueTransitions(config: any, issueKey: string): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    const result = await jiraClient.issues.getTransitions({ issueIdOrKey: issueKey });
    return result.transitions || [];
  } catch (error) {
    logger.error(`Error getting Jira issue transitions:`, error);
    throw error;
  }
}

/**
 * Helper function to get a list of comments for an issue from Jira
 */
async function getIssueComments(config: any, issueKey: string, startAt = 0, maxResults = 20): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    return await jiraClient.issueComments.getComments({
      issueIdOrKey: issueKey,
      startAt,
      maxResults
    });
  } catch (error) {
    logger.error(`Error getting Jira issue comments:`, error);
    throw error;
  }
}

/**
 * Hàm chuyển ADF sang text thuần
 */
function extractTextFromADF(adf: any): string {
  if (!adf || typeof adf === 'string') return adf || '';
  let text = '';
  if (adf.content) {
    adf.content.forEach((node: any) => {
      if (node.type === 'paragraph' && node.content) {
        node.content.forEach((inline: any) => {
          if (inline.type === 'text') {
            text += inline.text;
          }
        });
        text += '\n';
      }
    });
  }
  return text.trim();
}

/**
 * Format Jira issue data to standardized format
 */
function formatIssueData(issue: any, baseUrl: string): any {
  return {
    id: issue.id,
    key: issue.key,
    summary: issue.fields?.summary || '',
    description: extractTextFromADF(issue.fields?.description),
    rawDescription: issue.fields?.description || null,
    status: {
      name: issue.fields?.status?.name || 'Unknown',
      id: issue.fields?.status?.id || '0'
    },
    assignee: issue.fields?.assignee ? {
      displayName: issue.fields.assignee.displayName,
      accountId: issue.fields.assignee.accountId
    } : null,
    reporter: issue.fields?.reporter ? {
      displayName: issue.fields.reporter.displayName,
      accountId: issue.fields.reporter.accountId
    } : null,
    priority: issue.fields?.priority ? {
      name: issue.fields.priority.name,
      id: issue.fields.priority.id
    } : null,
    labels: issue.fields?.labels || [],
    attachments: (issue.fields?.attachment || []).map((att: any) => ({
      id: att.id,
      filename: att.filename,
      author: att.author ? {
        displayName: att.author.displayName,
        accountId: att.author.accountId
      } : null,
      created: att.created,
      size: att.size,
      mimeType: att.mimeType,
      content: att.content,
      thumbnail: att.thumbnail
    })),
    created: issue.fields?.created || null,
    updated: issue.fields?.updated || null,
    issueType: {
      name: issue.fields?.issuetype?.name || 'Unknown',
      id: issue.fields?.issuetype?.id || '0'
    },
    projectKey: issue.fields?.project?.key || '',
    projectName: issue.fields?.project?.name || '',
    url: `${baseUrl}/browse/${issue.key}`
  };
}

/**
 * Format Jira comment data to standardized format
 */
function formatCommentData(comment: any): any {
  return {
    id: comment.id,
    body: extractTextFromADF(comment.body),
    rawBody: comment.body || '',
    author: comment.author ? {
      displayName: comment.author.displayName,
      accountId: comment.author.accountId
    } : null,
    created: comment.created || null,
    updated: comment.updated || null
  };
}

/**
 * Register resources related to Jira issues
 * @param server MCP Server instance
 */
export function registerIssueResources(server: McpServer) {
  logger.info('Registering Jira issue resources...');

  // Resource: Issues list (with pagination and JQL support)
  server.resource(
    'jira-issues-list',
    new ResourceTemplate('jira://issues', {
      list: async (_extra) => {
        return {
          resources: [
            {
              uri: 'jira://issues',
              name: 'Jira Issues',
              description: 'List and search all Jira issues',
              mimeType: 'application/json'
            }
          ]
        };
      }
    }),
    async (uri, params, _extra) => {
      try {
        const config = Config.getAtlassianConfigFromEnv();
        const { limit, offset } = Resources.extractPagingParams(params);
        const jql = params.jql ? Array.isArray(params.jql) ? params.jql[0] : params.jql : '';
        const project = params.project ? Array.isArray(params.project) ? params.project[0] : params.project : '';
        const status = params.status ? Array.isArray(params.status) ? params.status[0] : params.status : '';

        // Build JQL query based on parameters
        let jqlQuery = jql;
        if (project && !jqlQuery.includes('project=')) {
          jqlQuery = jqlQuery ? `${jqlQuery} AND project = ${project}` : `project = ${project}`;
        }
        if (status && !jqlQuery.includes('status=')) {
          jqlQuery = jqlQuery ? `${jqlQuery} AND status = "${status}"` : `status = "${status}"`;
        }

        logger.info(`Searching Jira issues with JQL: ${jqlQuery || 'All issues'}`);
        const response = await searchIssuesApi(config, jqlQuery, limit);

        // Format issues data
        const formattedIssues = response.issues.map((issue: any) => formatIssueData(issue, config.baseUrl));

        const uriString = typeof uri === 'string' ? uri : uri.href;
        return Resources.createStandardResource(
          uriString,
          formattedIssues,
          'issues',
          issuesListSchema,
          response.total,
          limit,
          offset,
          `${config.baseUrl}/issues/?jql=${encodeURIComponent(jqlQuery)}`
        );
      } catch (error) {
        logger.error('Error getting Jira issues:', error);
        throw error;
      }
    }
  );

  // Resource: Issue details
  server.resource(
    'jira-issue-details',
    new ResourceTemplate('jira://issues/{issueKey}', {
      list: async (_extra) => {
        return {
          resources: [
            {
              uri: 'jira://issues/{issueKey}',
              name: 'Jira Issue Details',
              description: 'Get details for a specific Jira issue by key. Replace {issueKey} with the issue key.',
              mimeType: 'application/json'
            }
          ]
        };
      }
    }),
    async (uri, params, _extra) => {
      try {
        const config = Config.getAtlassianConfigFromEnv();
        let normalizedIssueKey = Array.isArray(params.issueKey) ? params.issueKey[0] : params.issueKey;

        if (!normalizedIssueKey) {
          throw new Error('Missing issueKey in URI');
        }

        logger.info(`Getting details for Jira issue: ${normalizedIssueKey}`);
        const issue = await getIssue(config, normalizedIssueKey);
        const formattedIssue = formatIssueData(issue, config.baseUrl);

        const uriString = typeof uri === 'string' ? uri : uri.href;
        return Resources.createStandardResource(
          uriString,
          [formattedIssue],
          'issue',
          issueSchema,
          1,
          1,
          0,
          `${config.baseUrl}/browse/${normalizedIssueKey}`
        );
      } catch (error) {
        logger.error(`Error getting Jira issue details:`, error);
        throw error;
      }
    }
  );

  // Resource: Issue transitions (available actions/status changes)
  server.resource(
    'jira-issue-transitions',
    new ResourceTemplate('jira://issues/{issueKey}/transitions', {
      list: async (_extra) => {
        return {
          resources: [
            {
              uri: 'jira://issues/{issueKey}/transitions',
              name: 'Jira Issue Transitions',
              description: 'List available transitions for a Jira issue. Replace {issueKey} with the issue key.',
              mimeType: 'application/json'
            }
          ]
        };
      }
    }),
    async (uri, params, _extra) => {
      try {
        const config = Config.getAtlassianConfigFromEnv();
        let normalizedIssueKey = Array.isArray(params.issueKey) ? params.issueKey[0] : params.issueKey;

        if (!normalizedIssueKey) {
          throw new Error('Missing issueKey in URI');
        }

        logger.info(`Getting transitions for Jira issue: ${normalizedIssueKey}`);
        const transitions = await getIssueTransitions(config, normalizedIssueKey);

        // Format transitions data
        const formattedTransitions = transitions.map((t: any) => ({
          id: t.id,
          name: t.name,
          to: {
            id: t.to.id,
            name: t.to.name
          }
        }));

        const uriString = typeof uri === 'string' ? uri : uri.href;
        return Resources.createStandardResource(
          uriString,
          formattedTransitions,
          'transitions',
          transitionsListSchema,
          formattedTransitions.length,
          formattedTransitions.length,
          0,
          `${config.baseUrl}/browse/${normalizedIssueKey}`
        );
      } catch (error) {
        logger.error(`Error getting Jira issue transitions:`, error);
        throw error;
      }
    }
  );

  // Resource: Issue comments
  server.resource(
    'jira-issue-comments',
    new ResourceTemplate('jira://issues/{issueKey}/comments', {
      list: async (_extra) => {
        return {
          resources: [
            {
              uri: 'jira://issues/{issueKey}/comments',
              name: 'Jira Issue Comments',
              description: 'List comments for a Jira issue. Replace {issueKey} with the issue key.',
              mimeType: 'application/json'
            }
          ]
        };
      }
    }),
    async (uri, params, _extra) => {
      try {
        const config = Config.getAtlassianConfigFromEnv();
        let normalizedIssueKey = Array.isArray(params.issueKey) ? params.issueKey[0] : params.issueKey;

        if (!normalizedIssueKey) {
          throw new Error('Missing issueKey in URI');
        }

        const { limit, offset } = Resources.extractPagingParams(params);
        logger.info(`Getting comments for Jira issue: ${normalizedIssueKey}`);
        const commentData = await getIssueComments(config, normalizedIssueKey, offset, limit);

        // Format comments data
        const formattedComments = (commentData.comments || []).map((c: any) => formatCommentData(c));

        const uriString = typeof uri === 'string' ? uri : uri.href;
        return Resources.createStandardResource(
          uriString,
          formattedComments,
          'comments',
          commentsListSchema,
          commentData.total || formattedComments.length,
          limit,
          offset,
          `${config.baseUrl}/browse/${normalizedIssueKey}`
        );
      } catch (error) {
        logger.error(`Error getting Jira issue comments:`, error);
        throw error;
      }
    }
  );

  // Resource: Issue attachments
  server.resource(
    'jira-issue-attachments',
    new ResourceTemplate('jira://issues/{issueKey}/attachments', {
      list: async (_extra) => {
        return {
          resources: [
            {
              uri: 'jira://issues/{issueKey}/attachments',
              name: 'Jira Issue Attachments',
              description: 'List attachments for a Jira issue. Replace {issueKey} with the issue key.',
              mimeType: 'application/json'
            }
          ]
        };
      }
    }),
    async (uri, params, _extra) => {
      try {
        const config = Config.getAtlassianConfigFromEnv();
        let normalizedIssueKey = Array.isArray(params.issueKey) ? params.issueKey[0] : params.issueKey;

        if (!normalizedIssueKey) {
          throw new Error('Missing issueKey in URI');
        }

        logger.info(`Getting attachments for Jira issue: ${normalizedIssueKey}`);
        const issue = await getIssue(config, normalizedIssueKey);

        // Extract and format attachments
        const attachments = (issue.fields?.attachment || []).map((att: any) => ({
          id: att.id,
          filename: att.filename,
          author: att.author ? {
            displayName: att.author.displayName,
            accountId: att.author.accountId
          } : null,
          created: att.created,
          size: att.size,
          mimeType: att.mimeType,
          content: att.content,
          thumbnail: att.thumbnail,
          uri: `jira://attachments/${att.id}` // MCP Resource URI
        }));

        const uriString = typeof uri === 'string' ? uri : uri.href;

        // Define simple schema for attachment list
        const attachmentListSchema = {
          type: "object",
          properties: {
            attachments: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  id: { type: "string" },
                  filename: { type: "string" },
                  uri: { type: "string", description: "MCP Resource URI to download content" }
                }
              }
            },
            metadata: standardMetadataSchema
          }
        };

        return Resources.createStandardResource(
          uriString,
          attachments,
          'attachments',
          attachmentListSchema,
          attachments.length,
          attachments.length,
          0,
          `${config.baseUrl}/browse/${normalizedIssueKey}`
        );
      } catch (error) {
        logger.error(`Error getting Jira issue attachments:`, error);
        throw error;
      }
    }
  );

  logger.info('Jira issue resources registered successfully');
}
