import { AtlassianConfig, getJiraV2Client, logger } from './atlassian-api-base.js';
import { ApiError, ApiErrorType } from './error-handler.js';

// Helper: Fetch Jira create metadata for a project/issueType
export async function fetchJiraCreateMeta(
  config: AtlassianConfig,
  projectKey: string,
  issueType: string
): Promise<Record<string, any>> {
  // const headers = createBasicHeaders(config.email, config.apiToken);
  // const baseUrl = normalizeAtlassianBaseUrl(config.baseUrl);
  // // Lấy metadata cho project và issueType (dùng name hoặc id)
  // const url = `${baseUrl}/rest/api/2/issue/createmeta?projectKeys=${encodeURIComponent(projectKey)}&issuetypeNames=${encodeURIComponent(issueType)}&expand=projects.issuetypes.fields`;
  // const response = await fetch(url, { headers, credentials: 'omit' });
  // if (!response.ok) {
  //   const responseText = await response.text();
  //   logger.error(`Jira API error (createmeta, ${response.status}):`, responseText);
  //   throw new Error(`Jira API error (createmeta): ${response.status} ${responseText}`);
  // }
  // const meta = await response.json();
  const jiraClient = getJiraV2Client(config);
  const meta = await jiraClient.issues.getCreateIssueMeta({ projectKeys: [projectKey], issuetypeNames: [issueType] });
  // Trả về object các trường hợp lệ
  try {
    const fields = meta.projects?.[0]?.issuetypes?.[0]?.fields || {};
    return fields;
  } catch (e) {
    logger.error('Cannot parse createmeta fields', e);
    return {};
  }
}

// Create a new Jira issue (fix: chỉ gửi các trường có trong createmeta)
export async function createIssue(
  config: AtlassianConfig,
  projectKey: string,
  summary: string,
  description?: string,
  issueType: string = "Task",
  additionalFields: Record<string, any> = {}
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);

    // Lấy metadata các trường hợp lệ
    const createmetaFields = await fetchJiraCreateMeta(config, projectKey, issueType);

    // Chỉ map các trường có trong createmeta
    const safeFields: Record<string, any> = {};
    let labelsToUpdate: string[] | undefined = undefined;
    for (const key of Object.keys(additionalFields)) {
      if (createmetaFields[key]) {
        safeFields[key] = additionalFields[key];
      } else {
        logger.warn(`[createIssue] Field '${key}' is not available on create screen for project ${projectKey} / issueType ${issueType}, will be ignored.`);
        // Nếu là labels thì lưu lại để update sau
        if (key === 'labels') {
          labelsToUpdate = additionalFields[key];
        }
      }
    }

    const fields: any = {
      project: { key: projectKey },
      summary: summary,
      issuetype: { name: issueType },
      ...safeFields,
    };

    if (description && createmetaFields['description']) {
      fields.description = description;
    }

    logger.debug(`Creating issue in project ${projectKey} via jira.js`);
    const newIssue = await jiraClient.issues.createIssue({ fields });

    // Nếu không tạo được labels khi tạo issue, update lại ngay sau khi tạo
    if (labelsToUpdate && newIssue && newIssue.key) {
      logger.info(`[createIssue] Updating labels for issue ${newIssue.key} ngay sau khi tạo (do không khả dụng trên màn hình tạo issue)`);
      try {
        await jiraClient.issues.editIssue({
          issueIdOrKey: newIssue.key,
          fields: { labels: labelsToUpdate }
        });
        logger.info(`[createIssue] Labels updated for issue ${newIssue.key}`);
      } catch (updateError) {
        logger.error(`[createIssue] Failed to update labels for issue ${newIssue.key}:`, updateError);
      }
    }

    return newIssue;
  } catch (error: any) {
    logger.error(`Error creating issue:`, error);
    if (error instanceof ApiError) throw error;
    const statusCode = error.response?.status || 500;
    const responseText = error.response?.data ? JSON.stringify(error.response.data) : (error.message || String(error));
    throw new ApiError(
      ApiErrorType.SERVER_ERROR,
      `Jira API error: ${responseText}`,
      statusCode,
      error
    );
  }
}

// Update a Jira issue
export async function updateIssue(
  config: AtlassianConfig,
  issueIdOrKey: string,
  fields: Record<string, any>
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Updating issue ${issueIdOrKey} via jira.js`);
    await jiraClient.issues.editIssue({
      issueIdOrKey,
      fields
    });
    return {
      success: true,
      message: `Issue ${issueIdOrKey} updated successfully`,
    };
  } catch (error: any) {
    logger.error(`Error updating issue ${issueIdOrKey}:`, error);
    if (error instanceof ApiError) throw error;
    const statusCode = error.response?.status || 500;
    throw new ApiError(
      ApiErrorType.SERVER_ERROR,
      `Jira API error updateIssue: ${error.message || String(error)}`,
      statusCode,
      error
    );
  }
}

// Change issue status
export async function transitionIssue(
  config: AtlassianConfig,
  issueIdOrKey: string,
  transitionId: string,
  comment?: string
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    const transitionData: any = {
      issueIdOrKey,
      transition: {
        id: transitionId,
      },
    };
    if (comment) {
      transitionData.update = {
        comment: [
          {
            add: {
              body: comment,
            },
          },
        ],
      };
    }
    logger.debug(`Transitioning issue ${issueIdOrKey} to status ID ${transitionId} via jira.js`);
    await jiraClient.issues.doTransition(transitionData);
    return {
      success: true,
      message: `Issue ${issueIdOrKey} transitioned successfully`,
      transitionId,
    };
  } catch (error: any) {
    logger.error(`Error transitioning issue ${issueIdOrKey}:`, error);
    if (error instanceof ApiError) throw error;
    const statusCode = error.response?.status || 500;
    throw new ApiError(
      ApiErrorType.SERVER_ERROR,
      `Jira API error transitionIssue: ${error.message || String(error)}`,
      statusCode,
      error
    );
  }
}

// Assign issue to a user
export async function assignIssue(
  config: AtlassianConfig,
  issueIdOrKey: string,
  accountId: string | null
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Assigning issue ${issueIdOrKey} to account ID ${accountId || "UNASSIGNED"} via jira.js`);
    await jiraClient.issues.assignIssue({
      issueIdOrKey,
      accountId
    });
    return {
      success: true,
      message: accountId
        ? `Issue ${issueIdOrKey} assigned successfully`
        : `Issue ${issueIdOrKey} unassigned successfully`,
    };
  } catch (error: any) {
    logger.error(`Error assigning issue ${issueIdOrKey}:`, error);
    if (error instanceof ApiError) throw error;
    const statusCode = error.response?.status || 500;
    throw new ApiError(
      ApiErrorType.SERVER_ERROR,
      `Jira API error assignIssue: ${error.message || String(error)}`,
      statusCode,
      error
    );
  }
}

// Create a new dashboard
export async function createDashboard(config: AtlassianConfig, data: { name: string, description?: string, sharePermissions?: any[] }): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Creating dashboard: ${data.name} via jira.js`);
    return await jiraClient.dashboards.createDashboard({
      name: data.name,
      description: data.description,
      sharePermissions: data.sharePermissions as any
    });
  } catch (error: any) {
    logger.error(`Error creating dashboard:`, error);
    throw error;
  }
}

// Update a dashboard
export async function updateDashboard(config: AtlassianConfig, dashboardId: string, data: { name?: string, description?: string, sharePermissions?: any[] }): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Updating dashboard ${dashboardId} via jira.js`);
    return await jiraClient.dashboards.updateDashboard({
      id: dashboardId, // Keep as string for UpdateDashboard
      name: data.name || "", // Mandatory in type
      description: data.description,
      sharePermissions: data.sharePermissions as any,
      editPermissions: [] // Mandatory in type
    });
  } catch (error: any) {
    logger.error(`Error updating dashboard ${dashboardId}:`, error);
    throw error;
  }
}

// Add a gadget to a dashboard
export async function addGadgetToDashboard(config: AtlassianConfig, dashboardId: string, data: { uri: string, color?: string, position?: any, title?: string, properties?: any }): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Adding gadget to dashboard ${dashboardId} via jira.js`);
    return await (jiraClient.dashboards as any).addGadget({
      dashboardId: Number(dashboardId),
      ...data
    });
  } catch (error: any) {
    logger.error(`Error adding gadget to dashboard ${dashboardId}:`, error);
    throw error;
  }
}

// Remove a gadget from a dashboard
export async function removeGadgetFromDashboard(config: AtlassianConfig, dashboardId: string, gadgetId: string): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Removing gadget ${gadgetId} from dashboard ${dashboardId} via jira.js`);
    return await (jiraClient.dashboards as any).removeGadget({
      dashboardId: Number(dashboardId),
      gadgetId: Number(gadgetId)
    });
  } catch (error: any) {
    logger.error(`Error removing gadget ${gadgetId} from dashboard ${dashboardId}:`, error);
    throw error;
  }
}

// Create a new filter
export async function createFilter(
  config: AtlassianConfig,
  name: string,
  jql: string,
  description?: string,
  favourite?: boolean
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    const data: any = {
      name,
      jql,
      description: description || '',
      favourite: favourite !== undefined ? favourite : false
    };
    logger.debug(`Creating Jira filter: ${name} via jira.js`);
    return await jiraClient.filters.createFilter(data);
  } catch (error: any) {
    logger.error(`Error creating Jira filter:`, error);
    throw error;
  }
}

// Update a filter
export async function updateFilter(
  config: AtlassianConfig,
  filterId: string,
  updateData: { name?: string; jql?: string; description?: string; favourite?: boolean; sharePermissions?: any[] }
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Updating Jira filter ${filterId} via jira.js`);
    // Chỉ build payload với các trường hợp lệ
    const allowedFields = ['name', 'jql', 'description', 'favourite', 'sharePermissions'] as const;
    type AllowedField = typeof allowedFields[number];
    const data: any = { id: Number(filterId) };
    for (const key of allowedFields) {
      if (updateData[key as AllowedField] !== undefined) {
        data[key] = updateData[key as AllowedField];
      }
    }
    return await jiraClient.filters.updateFilter(data);
  } catch (error: any) {
    logger.error(`Error updating Jira filter ${filterId}:`, error);
    throw error;
  }
}

// Delete a filter
export async function deleteFilter(
  config: AtlassianConfig,
  filterId: string
): Promise<void> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Deleting Jira filter ${filterId} via jira.js`);
    await jiraClient.filters.deleteFilter({ id: Number(filterId) });
  } catch (error: any) {
    logger.error(`Error deleting Jira filter ${filterId}:`, error);
    throw error;
  }
}

// Lấy danh sách tất cả gadget có sẵn để thêm vào dashboard
export async function getJiraAvailableGadgets(config: AtlassianConfig): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Fetching available gadgets via jira.js`);
    return await jiraClient.dashboards.getAllAvailableDashboardGadgets();
  } catch (error: any) {
    logger.error(`Error fetching available gadgets:`, error);
    throw error;
  }
}

// Add a comment to an issue
export async function addComment(
  config: AtlassianConfig,
  issueIdOrKey: string,
  comment: string
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Adding comment to issue ${issueIdOrKey} via sendRequest`);
    return await (jiraClient as any).sendRequest({
      url: `/rest/api/2/issue/${issueIdOrKey}/comment`,
      method: 'POST',
      data: { body: comment }
    });
  } catch (error: any) {
    logger.error(`Error adding comment to issue ${issueIdOrKey}:`, error);
    throw error;
  }
}

// Add a worklog to an issue
export async function addWorklog(
  config: AtlassianConfig,
  issueIdOrKey: string,
  timeSpent: string, // e.g. "3h 30m"
  comment?: string,
  started?: string // ISO 8601 date-time string
): Promise<any> {
  try {
    const jiraClient = getJiraV2Client(config);
    logger.debug(`Adding worklog to issue ${issueIdOrKey} via jira.js`);
    return await jiraClient.issueWorklogs.addWorklog({
      issueIdOrKey,
      timeSpent,
      comment,
      started
    });
  } catch (error: any) {
    logger.error(`Error adding worklog to issue ${issueIdOrKey}:`, error);
    throw error;
  }
}