/**
 * Monday.com GraphQL Client
 * All requests are POST to https://api.monday.com/v2
 */

import axios, { AxiosInstance } from "axios";
import type {
  Board,
  Item,
  Group,
  Update,
  User,
  Team,
  Workspace,
  Webhook,
  MondayResponse,
  GraphQLResponse,
  GetBoardsOptions,
  GetItemsOptions,
  CreateBoardOptions,
  CreateItemOptions,
  ChangeColumnValueOptions,
  CreateGroupOptions,
  CreateUpdateOptions,
  CreateWebhookOptions,
  Complexity,
} from "../types/index.js";

export class MondayClient {
  private client: AxiosInstance;
  private lastComplexity?: Complexity;

  constructor(apiKey: string) {
    this.client = axios.create({
      baseURL: "https://api.monday.com/v2",
      headers: {
        "Content-Type": "application/json",
        Authorization: apiKey,
      },
      timeout: 30000,
    });
  }

  /**
   * Get the last query complexity data
   */
  getComplexity(): Complexity | undefined {
    return this.lastComplexity;
  }

  /**
   * Execute a raw GraphQL query
   */
  private async query<T = any>(
    query: string,
    variables?: Record<string, any>
  ): Promise<MondayResponse<T>> {
    const response = await this.client.post<GraphQLResponse<T>>("", {
      query,
      variables,
    });

    if (response.data.errors && response.data.errors.length > 0) {
      throw new Error(
        `Monday API Error: ${response.data.errors.map((e) => e.message).join(", ")}`
      );
    }

    // Parse complexity from response headers or extensions
    // Monday returns complexity in the response data
    const result: MondayResponse<T> = {
      data: response.data.data!,
      account_id: response.data.account_id,
    };

    return result;
  }

  // ============================================================================
  // Board Methods
  // ============================================================================

  /**
   * Get multiple boards
   */
  async getBoards(options: GetBoardsOptions = {}): Promise<Board[]> {
    const {
      limit = 25,
      page = 1,
      state = "active",
      board_kind,
      workspace_ids,
    } = options;

    let args: string[] = [`limit: ${limit}`, `page: ${page}`];
    if (state !== "all") args.push(`state: ${state}`);
    if (board_kind) args.push(`board_kind: ${board_kind}`);
    if (workspace_ids && workspace_ids.length > 0) {
      args.push(`workspace_ids: [${workspace_ids.join(", ")}]`);
    }

    const query = `
      query {
        boards(${args.join(", ")}) {
          id
          name
          description
          board_kind
          state
          workspace_id
          owner_id
          permissions
          created_at
          updated_at
          items_count
          columns {
            id
            title
            type
            description
            settings_str
            archived
            width
          }
          groups {
            id
            title
            color
            position
            archived
          }
        }
      }
    `;

    const result = await this.query<{ boards: Board[] }>(query);
    return result.data.boards;
  }

  /**
   * Get a single board by ID
   */
  async getBoard(boardId: string): Promise<Board> {
    const query = `
      query {
        boards(ids: [${boardId}]) {
          id
          name
          description
          board_kind
          state
          workspace_id
          folder_id
          owner_id
          permissions
          created_at
          updated_at
          items_count
          columns {
            id
            title
            type
            description
            settings_str
            archived
            width
          }
          groups {
            id
            title
            color
            position
            archived
          }
        }
      }
    `;

    const result = await this.query<{ boards: Board[] }>(query);
    if (!result.data.boards || result.data.boards.length === 0) {
      throw new Error(`Board ${boardId} not found`);
    }
    return result.data.boards[0];
  }

  /**
   * Create a new board
   */
  async createBoard(options: CreateBoardOptions): Promise<Board> {
    const {
      board_name,
      board_kind,
      description,
      workspace_id,
      folder_id,
      template_id,
    } = options;

    let args: string[] = [
      `board_name: "${board_name}"`,
      `board_kind: ${board_kind}`,
    ];
    if (description) args.push(`description: "${description}"`);
    if (workspace_id) args.push(`workspace_id: ${workspace_id}`);
    if (folder_id) args.push(`folder_id: ${folder_id}`);
    if (template_id) args.push(`template_id: ${template_id}`);

    const query = `
      mutation {
        create_board(${args.join(", ")}) {
          id
          name
          description
          board_kind
          state
          workspace_id
          owner_id
        }
      }
    `;

    const result = await this.query<{ create_board: Board }>(query);
    return result.data.create_board;
  }

  // ============================================================================
  // Item Methods
  // ============================================================================

  /**
   * Get items from a board
   */
  async getItems(boardId: string, options: GetItemsOptions = {}): Promise<Item[]> {
    const { limit = 25, page = 1, ids, newest_first } = options;

    let boardArgs: string[] = [`ids: [${boardId}]`];
    let itemsArgs: string[] = [`limit: ${limit}`];
    
    if (page) itemsArgs.push(`page: ${page}`);
    if (ids && ids.length > 0) itemsArgs.push(`ids: [${ids.join(", ")}]`);
    if (newest_first !== undefined) itemsArgs.push(`newest_first: ${newest_first}`);

    const query = `
      query {
        boards(${boardArgs.join(", ")}) {
          items_page(${itemsArgs.join(", ")}) {
            cursor
            items {
              id
              name
              state
              created_at
              updated_at
              creator_id
              group {
                id
                title
              }
              column_values {
                id
                text
                value
                type
              }
            }
          }
        }
      }
    `;

    const result = await this.query<{
      boards: Array<{ items_page: { items: Item[] } }>;
    }>(query);

    if (!result.data.boards || result.data.boards.length === 0) {
      return [];
    }

    return result.data.boards[0].items_page.items;
  }

  /**
   * Get a single item by ID
   */
  async getItem(itemId: string): Promise<Item> {
    const query = `
      query {
        items(ids: [${itemId}]) {
          id
          name
          state
          created_at
          updated_at
          creator_id
          board {
            id
            name
          }
          group {
            id
            title
          }
          column_values {
            id
            text
            value
            type
          }
        }
      }
    `;

    const result = await this.query<{ items: Item[] }>(query);
    if (!result.data.items || result.data.items.length === 0) {
      throw new Error(`Item ${itemId} not found`);
    }
    return result.data.items[0];
  }

  /**
   * Create a new item
   */
  async createItem(options: CreateItemOptions): Promise<Item> {
    const {
      board_id,
      group_id,
      item_name,
      column_values,
      create_labels_if_missing,
    } = options;

    let args: string[] = [
      `board_id: ${board_id}`,
      `item_name: "${item_name}"`,
    ];
    if (group_id) args.push(`group_id: "${group_id}"`);
    if (column_values) {
      const jsonStr = JSON.stringify(JSON.stringify(column_values));
      args.push(`column_values: ${jsonStr}`);
    }
    if (create_labels_if_missing !== undefined) {
      args.push(`create_labels_if_missing: ${create_labels_if_missing}`);
    }

    const query = `
      mutation {
        create_item(${args.join(", ")}) {
          id
          name
          state
          created_at
          creator_id
          board {
            id
            name
          }
          group {
            id
            title
          }
        }
      }
    `;

    const result = await this.query<{ create_item: Item }>(query);
    return result.data.create_item;
  }

  /**
   * Change a column value for an item
   */
  async changeColumnValue(options: ChangeColumnValueOptions): Promise<Item> {
    const { board_id, item_id, column_id, value } = options;

    const jsonValue = JSON.stringify(JSON.stringify(value));

    const query = `
      mutation {
        change_column_value(
          board_id: ${board_id}
          item_id: ${item_id}
          column_id: "${column_id}"
          value: ${jsonValue}
        ) {
          id
          name
        }
      }
    `;

    const result = await this.query<{ change_column_value: Item }>(query);
    return result.data.change_column_value;
  }

  // ============================================================================
  // Group Methods
  // ============================================================================

  /**
   * Create a new group
   */
  async createGroup(options: CreateGroupOptions): Promise<Group> {
    const { board_id, group_name, position_relative_method, relative_to } =
      options;

    let args: string[] = [
      `board_id: ${board_id}`,
      `group_name: "${group_name}"`,
    ];
    if (position_relative_method) {
      args.push(`position_relative_method: ${position_relative_method}`);
    }
    if (relative_to) args.push(`relative_to: "${relative_to}"`);

    const query = `
      mutation {
        create_group(${args.join(", ")}) {
          id
          title
          color
          position
        }
      }
    `;

    const result = await this.query<{ create_group: Group }>(query);
    return result.data.create_group;
  }

  // ============================================================================
  // Update Methods
  // ============================================================================

  /**
   * Get updates for an item
   */
  async getUpdates(itemId: string, limit = 25): Promise<Update[]> {
    const query = `
      query {
        items(ids: [${itemId}]) {
          updates(limit: ${limit}) {
            id
            body
            created_at
            updated_at
            creator_id
            text_body
            creator {
              id
              name
              email
            }
          }
        }
      }
    `;

    const result = await this.query<{
      items: Array<{ updates: Update[] }>;
    }>(query);

    if (!result.data.items || result.data.items.length === 0) {
      return [];
    }

    return result.data.items[0].updates || [];
  }

  /**
   * Create an update
   */
  async createUpdate(options: CreateUpdateOptions): Promise<Update> {
    const { item_id, body, parent_id } = options;

    let args: string[] = [`item_id: ${item_id}`, `body: "${body}"`];
    if (parent_id) args.push(`parent_id: ${parent_id}`);

    const query = `
      mutation {
        create_update(${args.join(", ")}) {
          id
          body
          created_at
          creator_id
          text_body
        }
      }
    `;

    const result = await this.query<{ create_update: Update }>(query);
    return result.data.create_update;
  }

  // ============================================================================
  // User, Team, Workspace Methods
  // ============================================================================

  /**
   * Get current user
   */
  async getUsers(limit = 50): Promise<User[]> {
    const query = `
      query {
        users(limit: ${limit}) {
          id
          name
          email
          url
          photo_thumb
          is_guest
          enabled
          created_at
          title
          phone
          location
          time_zone_identifier
        }
      }
    `;

    const result = await this.query<{ users: User[] }>(query);
    return result.data.users;
  }

  /**
   * Get teams
   */
  async getTeams(limit = 50): Promise<Team[]> {
    const query = `
      query {
        teams(limit: ${limit}) {
          id
          name
          picture_url
          users {
            id
            name
            email
          }
        }
      }
    `;

    const result = await this.query<{ teams: Team[] }>(query);
    return result.data.teams;
  }

  /**
   * Get workspaces
   */
  async getWorkspaces(limit = 50): Promise<Workspace[]> {
    const query = `
      query {
        workspaces(limit: ${limit}) {
          id
          name
          kind
          description
          created_at
        }
      }
    `;

    const result = await this.query<{ workspaces: Workspace[] }>(query);
    return result.data.workspaces;
  }

  // ============================================================================
  // Webhook Methods
  // ============================================================================

  /**
   * Create a webhook
   */
  async createWebhook(options: CreateWebhookOptions): Promise<Webhook> {
    const { board_id, url, event, config } = options;

    let args: string[] = [
      `board_id: ${board_id}`,
      `url: "${url}"`,
      `event: ${event}`,
    ];
    if (config) {
      const jsonStr = JSON.stringify(JSON.stringify(config));
      args.push(`config: ${jsonStr}`);
    }

    const query = `
      mutation {
        create_webhook(${args.join(", ")}) {
          id
          board_id
        }
      }
    `;

    const result = await this.query<{ create_webhook: Webhook }>(query);
    return result.data.create_webhook;
  }

  /**
   * Delete a webhook
   */
  async deleteWebhook(webhookId: string): Promise<{ id: string }> {
    const query = `
      mutation {
        delete_webhook(id: ${webhookId}) {
          id
        }
      }
    `;

    const result = await this.query<{ delete_webhook: { id: string } }>(query);
    return result.data.delete_webhook;
  }
}
