import { writeGeneratedFile } from "../../helpers/fs";
import { generateFileHeader } from "../types/fileHeader";
import { generateWebhookEventFunctionForList } from "../webhookEventFactory";

const FILE_NAME = "attribute.ts";

export function generateAttributeFetcher(outputDir: string): void {
  const content = `${generateFileHeader(FILE_NAME)}
import { AttioClient } from "./attioClient";
import { BaseFetcher } from "./base";
import { AttioWebhookEventPopulatedListener } from "./webhook";
import { AttioAttribute, AttioSelectOption, AttioStatus, WebhookEventDataByType } from "../types";

export interface AttioAttributeInput {
  data: {
    api_slug: string;
    title: string;
    description: string | null;
    type: string;
    is_required?: boolean;
    is_unique?: boolean;
    is_multiselect?: boolean;
    default_value: Record<string, any> | null;
    config?: Record<string, any>;
  };
}

export interface AttioSelectOptionInput {
  title: string;
}

export interface AttioStatusInput {
  data: {
    title: string;
    celebration_enabled?: boolean;
    target_time_in_status: string | null;
  };
}

export interface AttributeBasePathParams {
  target: "objects" | "lists";
  identifier: string;
}

export interface AttributeGetAllQueryParams {
  limit?: number;
  offset?: number;
  showArchived?: boolean;
}

export interface AttributeGetByIdParams extends AttributeBasePathParams {
  attributeId: string;
}

export interface AttributeGetSelectOptionByIdParams extends AttributeGetByIdParams {
  selectOptionId: string;
}

export interface AttributeGetStatusByIdParams extends AttributeGetByIdParams {
  statusId: string;
}

export class AttioAttributeFetcher extends BaseFetcher {
  constructor(client: AttioClient) {
    super(client);
  }

  createBaseUrl({ target, identifier }: AttributeBasePathParams): string {
    return \`/$\{target}/$\{identifier}/attributes\`;
  }

  async getAll(params: AttributeBasePathParams, query?: AttributeGetAllQueryParams): Promise<AttioAttribute[]> {
    return this.extractData(
      this.client.doFetch(this.createBaseUrl(params), {
        query: {
          ...query,
          show_archived: query?.showArchived,
        },
      })
    );
  }

  async getById({ attributeId, ...params }: AttributeGetByIdParams): Promise<AttioAttribute> {
    return this.extractData(
      this.client.doFetch(\`\${this.createBaseUrl(params)}/\${attributeId}\`)
    );
  }

  async create(params: AttributeBasePathParams, data: AttioAttributeInput): Promise<AttioAttribute> {
    return this.extractData(
      this.client.doFetch(this.createBaseUrl(params), {
        method: "POST",
        body: data,
      })
    );
  }

  async update({ attributeId, ...params }: AttributeGetByIdParams, data: AttioAttributeInput): Promise<AttioAttribute> {
    return this.extractData(
      this.client.doFetch(\`\${this.createBaseUrl(params)}/\${attributeId}\`, {
        method: "PUT",
        body: data,
      })
    );
  }

  async getAllSelectOptions({ attributeId, ...params }: AttributeGetByIdParams, query?: { showArchived?: boolean }): Promise<AttioSelectOption[]> {
    return this.extractData(
      this.client.doFetch(\`\${this.createBaseUrl(params)}/\${attributeId}/options\`, {
        query: {
          show_archived: query?.showArchived,
        },
      })
    );
  }

  async createSelectOption({ attributeId, ...params }: AttributeGetByIdParams, data: AttioSelectOptionInput): Promise<AttioSelectOption> {
    return this.extractData(
      this.client.doFetch(\`\${this.createBaseUrl(params)}/\${attributeId}/options\`, {
        method: "POST",
        body: data,
      })
    );
  }

  async updateSelectOption({ attributeId, selectOptionId, ...params }: AttributeGetSelectOptionByIdParams, data: AttioSelectOptionInput): Promise<AttioSelectOption> {
    return this.extractData(
      this.client.doFetch(\`$\{this.createBaseUrl(params)}/$\{attributeId}/options/$\{selectOptionId}\`, {
        method: "PUT",
        body: data,
      })
    );
  }

  async getAllStatuses({ attributeId, ...params }: AttributeGetByIdParams, query?: { showArchived?: boolean }): Promise<AttioStatus[]> {
    return this.extractData(
      this.client.doFetch(\`$\{this.createBaseUrl(params)}/$\{attributeId}/statuses\`, {
        query,
      })
    );
  }

  async createStatus({ attributeId, ...params }: AttributeGetByIdParams, data: AttioStatusInput): Promise<AttioStatus> {
    return this.extractData(
      this.client.doFetch(\`$\{this.createBaseUrl(params)}/$\{attributeId}/statuses\`, {
        method: "POST",
        body: data,
      })
    );
  }

  async updateStatus({ attributeId, statusId, ...params }: AttributeGetStatusByIdParams, data: AttioStatusInput): Promise<AttioStatus> {
    return this.extractData(
      this.client.doFetch(\`$\{this.createBaseUrl(params)}/$\{attributeId}/statuses/$\{statusId}\`, {
        method: "PUT",
        body: data,
      })
    );
  }

  ${generateWebhookEventFunctionForList({
    eventNames: ["list-attribute.created", "list-attribute.updated"],
    fetchCode: `
      this.getById({
        attributeId: payload.id.attribute_id,
        target: "lists",
        identifier: payload.id.list_id,
      })
    `.trim(),
    customPrefix: "onListAttribute",
    populatedType: "AttioAttribute",
  })}
  ${generateWebhookEventFunctionForList({
    eventNames: ["object-attribute.created", "object-attribute.updated"],
    fetchCode: `
      this.getById({
        attributeId: payload.id.attribute_id,
        target: "objects",
        identifier: payload.id.object_id,
      })
    `.trim(),
    customPrefix: "onObjectAttribute",
    populatedType: "AttioAttribute",
  })}
}`;

  writeGeneratedFile(outputDir, FILE_NAME, content);
}
