const DEFAULT_API_URL = "http://localhost:8080";

export class ProductierApiError extends Error {
  constructor(message, status, code, requestId) {
    super(message);
    this.name = "ProductierApiError";
    this.status = status;
    this.code = code ?? "unknown_error";
    this.requestId = requestId ?? null;
  }
}

function readErrorMessage(payload, fallback) {
  if (!payload || typeof payload !== "object") {
    return fallback;
  }
  if (payload.error && typeof payload.error === "object" && typeof payload.error.message === "string") {
    return payload.error.message;
  }
  if (typeof payload.message === "string") {
    return payload.message;
  }
  return fallback;
}

export function createProductierClient(options = {}) {
  const apiUrl = (options.apiUrl || process.env.PRODUCTIER_API_URL || DEFAULT_API_URL).replace(/\/+$/, "");
  const authCookie = options.authCookie || process.env.PRODUCTIER_AUTH_COOKIE || "";
  const fetchImpl = options.fetchImpl || globalThis.fetch;

  if (typeof fetchImpl !== "function") {
    throw new Error("fetch implementation is required");
  }

  async function requestJSON(method, path, { query = {}, body } = {}) {
    const url = new URL(`${apiUrl}${path}`);
    for (const [key, value] of Object.entries(query)) {
      if (value === undefined || value === null || value === "") {
        continue;
      }
      url.searchParams.set(key, String(value));
    }

    const headers = {
      ...(authCookie ? { Cookie: authCookie } : {}),
      Accept: "application/json"
    };
    const init = {
      method,
      headers
    };
    if (body !== undefined) {
      headers["Content-Type"] = "application/json";
      init.body = JSON.stringify(body);
    }

    const response = await fetchImpl(url, {
      ...init
    });

    let payload = null;
    try {
      payload = await response.json();
    } catch {
      payload = null;
    }

    if (!response.ok) {
      const message = readErrorMessage(payload, `request failed with status ${response.status}`);
      const code = payload?.error?.code;
      const requestId = payload?.error?.requestId || response.headers.get("x-request-id");
      throw new ProductierApiError(message, response.status, code, requestId);
    }

    return payload;
  }

  return {
    async listWorkspaces() {
      return requestJSON("GET", "/v1/workspaces");
    },
    async listBoardGroups(workspaceSlug) {
      return requestJSON("GET", "/v1/board-groups", { query: { workspaceSlug } });
    },
    async createBoardGroup(input) {
      return requestJSON("POST", "/v1/board-groups", { body: input });
    },
    async updateBoardGroup(groupId, input) {
      return requestJSON("PATCH", `/v1/board-groups/${encodeURIComponent(groupId)}`, { body: input });
    },
    async listTasks(workspaceSlug) {
      return requestJSON("GET", "/v1/tasks", { query: { workspaceSlug } });
    },
    async createTask(input) {
      return requestJSON("POST", "/v1/tasks", { body: input });
    },
    async updateTask(taskId, input) {
      return requestJSON("PATCH", `/v1/tasks/${encodeURIComponent(taskId)}`, { body: input });
    },
    async listCalendarEvents(workspaceSlug) {
      return requestJSON("GET", "/v1/calendar/events", { query: { workspaceSlug } });
    },
    async createCalendarEvent(input) {
      return requestJSON("POST", "/v1/calendar/events", { body: input });
    },
    async updateCalendarEvent(eventId, input) {
      return requestJSON("PATCH", `/v1/calendar/events/${encodeURIComponent(eventId)}`, { body: input });
    },
    async listNotes(workspaceSlug) {
      return requestJSON("GET", "/v1/notes", { query: { workspaceSlug } });
    },
    async createNote(input) {
      return requestJSON("POST", "/v1/notes", { body: input });
    },
    async updateNote(noteId, input) {
      return requestJSON("PATCH", `/v1/notes/${encodeURIComponent(noteId)}`, { body: input });
    },
    async listMailMessages(workspaceSlug, mailboxId) {
      return requestJSON("GET", "/v1/mail/messages", {
        query: {
          workspaceSlug,
          mailboxId
        }
      });
    },
    async listMailboxes(workspaceSlug) {
      return requestJSON("GET", "/v1/mailboxes", { query: { workspaceSlug } });
    },
    async connectMailbox(input) {
      return requestJSON("POST", "/v1/mailboxes", { body: input });
    },
    async syncMailbox(mailboxId) {
      return requestJSON("POST", `/v1/mailboxes/${encodeURIComponent(mailboxId)}/sync`);
    },
    async listOutgoingMails(workspaceSlug, mailboxId) {
      return requestJSON("GET", "/v1/mail/outgoing", {
        query: {
          workspaceSlug,
          mailboxId
        }
      });
    },
    async createOutgoingMail(input) {
      return requestJSON("POST", "/v1/mail/outgoing", { body: input });
    },
    async createTaskFromMail(messageId, input) {
      return requestJSON("POST", `/v1/mail/messages/${encodeURIComponent(messageId)}/create-task`, {
        body: input
      });
    }
  };
}
