import { z, IntegrationDefinitionProps, ActionDefinition } from '@botpress/sdk'
import { linearIdsSchema, userProfileSchema, issueSchema } from './schemas'

const _channels = ['issue'] as const

export type Target = {
  displayName: string
  tags: { [key: string]: string }
  channel: (typeof _channels)[number]
}

const findTarget = {
  title: 'Find Target',
  description: 'Find a target on Linear',
  input: {
    schema: z.object({
      query: z.string().min(2).title('Search query').describe('Issue title, description, or number'),
      channel: z.enum(['issue']).title('Channel').describe('The channel to search in'),
    }),
  },
  output: {
    schema: z.object({
      targets: z
        .array(
          z.object({
            displayName: z.string().title('Display Name').describe('The name of the issue'),
            tags: z.record(z.string()).title('Tags').describe('The tags applied to the issue'),
            channel: z.enum(['issue']).title('Channel').describe('The channel of the search result'),
          })
        )
        .title('Results')
        .describe('The list of issues found'),
    }),
  },
} as const satisfies ActionDefinition

const getIssue = {
  title: 'Get Issue',
  description: 'Get an issue by its ID',
  input: {
    schema: z.object({
      issueId: z.string().title('Issue ID').describe('The issue ID on Linear. Ex: {{event.payload.linearIds.issueId}}'),
    }),
  },
  output: {
    schema: issueSchema.title('Issue').describe('The issue found'),
  },
} as const satisfies ActionDefinition

const listIssues = {
  title: 'List Issues',
  description: 'List issues from Linear',
  input: {
    schema: z.object({
      count: z.number().optional().default(10).title('Fetch Amount').describe('The number of issues to return'),
      startCursor: z.string().optional().title('Start Cursor').describe('The cursor to start from'),
      teamId: z.string().optional().title('Team ID').describe('The team ID to filter by'),
      startDate: z.string().optional().title('Start Date').describe('Ignore issues created before this date'),
    }),
  },
  output: {
    schema: z.object({
      issues: z
        .array(issueSchema.extend({ linearIds: linearIdsSchema }))
        .title('Issues')
        .describe('The list of matching issues'),
      nextCursor: z.string().optional().title('Next Cursor').describe('The cursor to fetch the next page'),
    }),
  },
} as const satisfies ActionDefinition

const userSchema = z.object({
  id: z.string().title('ID').describe('The user ID on Linear'),
  email: z.string().title('Email').describe("The user's email address"),
  name: z.string().title('Name').describe("The user's nickname"),
  displayName: z.string().title('Display Name').describe("The user's display name"),
  avatarUrl: z.string().optional().title('Avatar URL').describe('The URL of the user avatar'),
  description: z
    .string()
    .optional()
    .title('Description')
    .describe("The user's description, such as their title or bio"),
  lastSeen: z.string().optional().title('Last Seen').describe('The last time the user was seen'),
  updatedAt: z.string().datetime().title('Updated At').describe('The last time the user was updated'),
})

const listUsers = {
  title: 'List Users',
  description: 'List users from Linear',
  input: {
    schema: z.object({
      count: z.number().optional().default(10).title('Fetch Amount').describe('The number of users to return'),
      startCursor: z.string().optional().title('Start Cursor').describe('The cursor to start from'),
    }),
  },
  output: {
    schema: z.object({
      users: z.array(userSchema).title('Users').describe('The list of matching users'),
      nextCursor: z.string().optional().title('Next Cursor').describe('The cursor to fetch the next page'),
    }),
  },
} as const satisfies ActionDefinition

const listTeams = {
  title: 'List Teams',
  description: 'List teams from Linear',
  input: {
    schema: z.object({}),
  },
  output: {
    schema: z.object({
      teams: z
        .array(
          z.object({
            id: z.string().title('ID').describe('The unique identifier of the entity'),
            key: z.string().title('Key').describe("The team's key"),
            name: z.string().title('Name').describe("The team's name"),
            description: z.string().optional().title('Description').describe("The team's description"),
            icon: z.string().optional().title('Icon').describe('The icon of the team'),
          })
        )
        .title('Teams')
        .describe('The list of teams'),
    }),
  },
} as const satisfies ActionDefinition

const listStates = {
  title: 'List States',
  description: 'List states from Linear',
  input: {
    schema: z.object({
      count: z.number().optional().default(10).title('Fetch Amount').describe('The number of states to return'),
      startCursor: z.string().optional().title('Start Cursor').describe('The cursor to start from'),
    }),
  },
  output: {
    schema: z.object({
      states: z
        .array(
          z.object({
            id: z.string().title('ID').describe('The unique identifier of the entity'),
            name: z.string().title('Name').describe("The state's name"),
          })
        )
        .title('States')
        .describe('The list of states'),
      nextCursor: z.string().optional().title('Next Cursor').describe('The cursor to fetch the next page'),
    }),
  },
} as const satisfies ActionDefinition

const markAsDuplicate = {
  title: 'Mark Issue as Duplicate',
  description: 'Mark an issue as a duplicate of another',
  input: {
    schema: z.object({
      issueId: z.string().title('Issue ID').describe('The issue ID on Linear. Ex: {{event.payload.linearIds.issueId}}'),
      relatedIssueId: z.string().title('Related Issue ID').describe('The ID of the existing issue on Linear'),
    }),
  },
  output: {
    schema: z.object({}),
  },
} as const satisfies ActionDefinition

const getUser = {
  title: 'Get User Profile',
  description: 'Get a user profile from Linear',
  input: {
    schema: z.object({
      linearUserId: z
        .string()
        .optional()
        .title('User ID')
        .describe(
          "The user's ID on Linear. Ex: {{event.payload.linearIds.creatorId}}. If omitted, returns the current user."
        ),
    }),
  },
  output: {
    schema: userProfileSchema.title('User').describe('The user profile'),
  },
} as const satisfies ActionDefinition

const updateIssue = {
  title: 'Update Issue',
  description: 'Update an issue on Linear',
  input: {
    schema: z.object({
      issueId: z.string().title('Issue ID').describe('The issue ID on Linear. Example: {{event.payload.id}}'),
      priority: z.number().optional().title('Priority').describe('0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low'),
      teamName: z
        .string()
        .optional()
        .title('Move to team...')
        .describe('Type a name to change the assigned team of the issue'),
      labels: z
        .array(z.string())
        .optional()
        .title('Set labels')
        .describe('One or multiple labels to assign to this issue'),
      project: z.string().optional().title('Associate to project...').describe('A project to associate to this issue'),
    }),
  },
  output: {
    schema: z.object({
      issue: issueSchema.optional().title('Issue').describe('The updated issue'),
    }),
  },
} as const satisfies ActionDefinition

const createIssue = {
  title: 'Create Issue',
  description: 'Create an issue on Linear',
  input: {
    schema: z.object({
      title: z.string().min(1).title('Title').describe("The issue's title"),
      description: z.string().title('Description').describe('The content of the issue'),
      priority: z.number().optional().title('Priority').describe('0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low'),
      teamName: z.string().title('Team Name').describe('Name of the team to assign the issue to'),
      labels: z.array(z.string()).optional().title('Labels').describe('One or multiple labels to assign to this issue'),
      project: z.string().optional().title('Project').describe('A project to associate to this issue'),
    }),
  },
  output: {
    schema: z.object({
      issue: issueSchema.title('Issue').describe('The created issue'),
    }),
  },
} as const satisfies ActionDefinition

const deleteIssue = {
  title: 'Delete Issue',
  description: 'Delete an issue on Linear',
  input: {
    schema: z.object({
      id: z.string().title('Issue ID').describe('The issue ID on Linear. Ex: {{event.payload.linearIds.issueId}}'),
    }),
  },
  output: {
    schema: z.object({}),
  },
} as const satisfies ActionDefinition

const sendRawGraphqlQuery = {
  title: 'Send Raw GraphQL Query',
  description: 'Send a raw GraphQL query to the linear API',
  input: {
    schema: z.object({
      query: z.string().title('Query').describe('The GraphQL query'),
      parameters: z
        .array(
          z.object({
            name: z.string().title('Name').describe('The parameter name'),
            value: z.any().title('Value').describe('The parameter value'),
          })
        )
        .optional()
        .title('Parameters')
        .describe('The query parameters'),
    }),
  },
  output: {
    schema: z.object({
      result: z.unknown().title('Result').describe('The query result'),
    }),
  },
} as const satisfies ActionDefinition

const resolveComment = {
  title: 'Resolve Comment',
  description: 'Resolve a comment by id',
  input: {
    schema: z.object({
      id: z.string().title('ID').describe('The comment ID'),
    }),
  },
  output: {
    schema: z.object({
      success: z.boolean().title('Success').describe('Whether the operation was successful'),
    }),
  },
} as const satisfies ActionDefinition

export const actions = {
  findTarget,
  listIssues,
  listTeams,
  listUsers,
  listStates,
  markAsDuplicate,
  getIssue,
  getUser,
  updateIssue,
  createIssue,
  deleteIssue,
  sendRawGraphqlQuery,
  resolveComment,
} as const satisfies IntegrationDefinitionProps['actions']
