import type { AsanaTask, AsanaSection, AsanaProject, AsanaComment } from "./types.js";
import { logger } from "../logger.js";

const ASANA_BASE = "https://app.asana.com/api/1.0";

export class AsanaClient {
  private token: string;
  private headers: Record<string, string>;

  constructor(token: string) {
    this.token = token;
    this.headers = {
      Authorization: `Bearer ${this.token}`,
      "Content-Type": "application/json",
      Accept: "application/json",
    };
  }

  private async request<T>(path: string, options: RequestInit = {}, retries = 3): Promise<T> {
    const url = `${ASANA_BASE}${path}`;

    for (let attempt = 1; attempt <= retries; attempt++) {
      const res = await fetch(url, {
        ...options,
        headers: { ...this.headers, ...options.headers },
      });

      if (res.status === 429) {
        const retryAfter = parseInt(res.headers.get("Retry-After") || "30");
        logger.warn("asana", `Rate limited, retrying in ${retryAfter}s (attempt ${attempt}/${retries})`);
        await new Promise((r) => setTimeout(r, retryAfter * 1000));
        continue;
      }

      if (!res.ok) {
        const body = await res.text();
        if (attempt < retries && res.status >= 500) {
          logger.warn("asana", `Server error ${res.status}, retrying (attempt ${attempt}/${retries})`);
          await new Promise((r) => setTimeout(r, 2000 * attempt));
          continue;
        }
        throw new Error(`Asana API ${res.status}: ${body}`);
      }

      const json = (await res.json()) as { data: T };
      return json.data;
    }

    throw new Error(`Asana API failed after ${retries} retries`);
  }

  // Get all workspaces
  async getWorkspaces(): Promise<Array<{ gid: string; name: string }>> {
    return this.request("/workspaces");
  }

  // Get all projects in a workspace
  async getProjects(workspaceGid: string): Promise<AsanaProject[]> {
    return this.request(`/workspaces/${workspaceGid}/projects?opt_fields=name`);
  }

  // Get all sections in a project
  async getSections(projectGid: string): Promise<AsanaSection[]> {
    return this.request(`/projects/${projectGid}/sections`);
  }

  // Get tasks in a project
  async getProjectTasks(projectGid: string): Promise<AsanaTask[]> {
    return this.request(
      `/projects/${projectGid}/tasks?opt_fields=name,notes,completed,assignee.name,tags.name,custom_fields,due_on,created_at,modified_at,memberships.project.name,memberships.section.name`
    );
  }

  // Get tasks in a section
  async getSectionTasks(sectionGid: string): Promise<AsanaTask[]> {
    return this.request(
      `/sections/${sectionGid}/tasks?opt_fields=name,notes,completed,assignee.name,tags.name,custom_fields,due_on,created_at,modified_at,memberships.project.name,memberships.section.name`
    );
  }

  // Get single task details
  async getTask(taskGid: string): Promise<AsanaTask> {
    return this.request(
      `/tasks/${taskGid}?opt_fields=name,notes,completed,assignee.name,tags.name,custom_fields,due_on,created_at,modified_at,memberships.project.name,memberships.section.name`
    );
  }

  // Move task to a section
  async moveTaskToSection(taskGid: string, sectionGid: string): Promise<void> {
    await this.request(`/sections/${sectionGid}/addTask`, {
      method: "POST",
      body: JSON.stringify({ data: { task: taskGid } }),
    });
  }

  // Update task (mark complete, change name, etc)
  async updateTask(taskGid: string, updates: Record<string, any>): Promise<AsanaTask> {
    return this.request(`/tasks/${taskGid}`, {
      method: "PUT",
      body: JSON.stringify({ data: updates }),
    });
  }

  // Add a comment to a task
  async addComment(taskGid: string, text: string): Promise<AsanaComment> {
    return this.request(`/tasks/${taskGid}/stories`, {
      method: "POST",
      body: JSON.stringify({ data: { text } }),
    });
  }

  // Get comments on a task
  async getComments(taskGid: string): Promise<AsanaComment[]> {
    return this.request(`/tasks/${taskGid}/stories?opt_fields=text,created_at`);
  }

  // Create a new task
  async createTask(projectGid: string, data: { name: string; notes?: string; due_on?: string }): Promise<AsanaTask> {
    return this.request("/tasks", {
      method: "POST",
      body: JSON.stringify({
        data: {
          ...data,
          projects: [projectGid],
        },
      }),
    });
  }

  // Get the authenticated user's GID
  async getMe(): Promise<{ gid: string; name: string }> {
    return this.request("/users/me?opt_fields=name");
  }

  // Get user task list for a workspace
  async getUserTaskList(userGid: string, workspaceGid: string): Promise<{ gid: string; name: string }> {
    return this.request(`/users/${userGid}/user_task_list?workspace=${workspaceGid}&opt_fields=name`);
  }

  // Get tasks from user task list (My Tasks / Recently Assigned)
  async getUserTasks(userTaskListGid: string): Promise<AsanaTask[]> {
    return this.request(
      `/user_task_lists/${userTaskListGid}/tasks?opt_fields=name,notes,completed,assignee.name,tags.name,custom_fields,due_on,created_at,modified_at,memberships.project.gid,memberships.project.name,memberships.section.gid,memberships.section.name,assignee_status`
    );
  }

  // Helper: Find section by name
  async findSection(projectGid: string, sectionName: string): Promise<AsanaSection | null> {
    const sections = await this.getSections(projectGid);
    return sections.find((s) => s.name.toLowerCase().includes(sectionName.toLowerCase())) || null;
  }

  // Helper: Get incomplete tasks from a section by name  
  async getIncompleteTasks(projectGid: string, sectionName: string): Promise<AsanaTask[]> {
    const section = await this.findSection(projectGid, sectionName);
    if (!section) return [];
    const tasks = await this.getSectionTasks(section.gid);
    return tasks.filter((t) => !t.completed);
  }
}
