import type { Database } from "bun:sqlite";

interface TaskFilters {
  orgId?: string | null;
  projectId?: string | null;
  status?: string | null;
  priority?: string | null;
  assigneeUserId?: string | null;
}

function toCamelCaseTask(row: Record<string, unknown>) {
  return {
    id: row.id,
    orgId: row.org_id,
    projectId: row.project_id,
    assigneeUserId: row.assignee_user_id,
    title: row.title,
    description: row.description,
    status: row.status,
    priority: row.priority,
    storyPoints: row.story_points,
    dueDate: row.due_date,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
    projectName: row.project_name,
    projectKey: row.project_key,
    assigneeName: row.assignee_name,
  };
}

export function listOrganizations(db: Database) {
  return db
    .query(`
      SELECT
        o.id,
        o.slug,
        o.name,
        o.plan,
        o.industry,
        o.created_at AS createdAt,
        COUNT(DISTINCT p.id) AS projectCount,
        COUNT(DISTINCT t.id) AS taskCount,
        COUNT(DISTINCT CASE WHEN t.status != 'done' THEN t.id END) AS openTaskCount
      FROM organizations o
      LEFT JOIN projects p ON p.org_id = o.id
      LEFT JOIN tasks t ON t.org_id = o.id
      GROUP BY o.id
      ORDER BY o.name
    `)
    .all();
}

export function getOrganizationSummary(db: Database, orgId: string) {
  const org = db
    .query(`
      SELECT
        o.id,
        o.slug,
        o.name,
        o.plan,
        o.industry,
        o.created_at AS createdAt,
        COUNT(DISTINCT u.id) AS userCount,
        COUNT(DISTINCT p.id) AS projectCount,
        COUNT(DISTINCT t.id) AS taskCount
      FROM organizations o
      LEFT JOIN users u ON u.org_id = o.id
      LEFT JOIN projects p ON p.org_id = o.id
      LEFT JOIN tasks t ON t.org_id = o.id
      WHERE o.id = ?
      GROUP BY o.id
    `)
    .get(orgId);

  if (!org) {
    return null;
  }

  const statusBreakdown = db
    .query(`
      SELECT status, COUNT(*) AS count
      FROM tasks
      WHERE org_id = ?
      GROUP BY status
      ORDER BY count DESC, status ASC
    `)
    .all(orgId);

  return {
    ...org,
    statusBreakdown,
  };
}

export function listUsers(db: Database, orgId?: string | null) {
  if (orgId) {
    return db
      .query(`
        SELECT
          id,
          org_id AS orgId,
          full_name AS fullName,
          email,
          role,
          timezone
        FROM users
        WHERE org_id = ?
        ORDER BY full_name
      `)
      .all(orgId);
  }

  return db
    .query(`
      SELECT
        id,
        org_id AS orgId,
        full_name AS fullName,
        email,
        role,
        timezone
      FROM users
      ORDER BY org_id, full_name
    `)
    .all();
}

export function listProjects(db: Database, orgId?: string | null) {
  const sql = `
    SELECT
      p.id,
      p.org_id AS orgId,
      p.key,
      p.name,
      p.status,
      p.owner_user_id AS ownerUserId,
      p.due_date AS dueDate,
      u.full_name AS ownerName,
      COUNT(t.id) AS taskCount
    FROM projects p
    LEFT JOIN users u ON u.id = p.owner_user_id
    LEFT JOIN tasks t ON t.project_id = p.id
    ${orgId ? "WHERE p.org_id = ?" : ""}
    GROUP BY p.id
    ORDER BY p.name
  `;

  return orgId ? db.query(sql).all(orgId) : db.query(sql).all();
}

export function listTasks(db: Database, filters: TaskFilters = {}) {
  const conditions: string[] = [];
  const values: string[] = [];

  if (filters.orgId) {
    conditions.push("t.org_id = ?");
    values.push(filters.orgId);
  }
  if (filters.projectId) {
    conditions.push("t.project_id = ?");
    values.push(filters.projectId);
  }
  if (filters.status) {
    conditions.push("t.status = ?");
    values.push(filters.status);
  }
  if (filters.priority) {
    conditions.push("t.priority = ?");
    values.push(filters.priority);
  }
  if (filters.assigneeUserId) {
    conditions.push("t.assignee_user_id = ?");
    values.push(filters.assigneeUserId);
  }

  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
  const rows = db
    .query(`
      SELECT
        t.*,
        p.name AS project_name,
        p.key AS project_key,
        u.full_name AS assignee_name
      FROM tasks t
      JOIN projects p ON p.id = t.project_id
      LEFT JOIN users u ON u.id = t.assignee_user_id
      ${whereClause}
      ORDER BY
        CASE t.priority
          WHEN 'urgent' THEN 1
          WHEN 'high' THEN 2
          WHEN 'medium' THEN 3
          ELSE 4
        END,
        t.due_date ASC,
        t.updated_at DESC
    `)
    .all(...values) as Record<string, unknown>[];

  return rows.map(toCamelCaseTask);
}

export function getTaskDetail(db: Database, taskId: string) {
  const row = db
    .query(`
      SELECT
        t.*,
        p.name AS project_name,
        p.key AS project_key,
        u.full_name AS assignee_name
      FROM tasks t
      JOIN projects p ON p.id = t.project_id
      LEFT JOIN users u ON u.id = t.assignee_user_id
      WHERE t.id = ?
    `)
    .get(taskId) as Record<string, unknown> | null;

  if (!row) {
    return null;
  }

  const labels = db
    .query(`
      SELECT l.id, l.name, l.color
      FROM task_labels tl
      JOIN labels l ON l.id = tl.label_id
      WHERE tl.task_id = ?
      ORDER BY l.name
    `)
    .all(taskId);

  const comments = db
    .query(`
      SELECT
        c.id,
        c.body,
        c.created_at AS createdAt,
        c.author_user_id AS authorUserId,
        u.full_name AS authorName
      FROM comments c
      JOIN users u ON u.id = c.author_user_id
      WHERE c.task_id = ?
      ORDER BY c.created_at ASC
    `)
    .all(taskId);

  return {
    ...toCamelCaseTask(row),
    labels,
    comments,
  };
}

export interface CreateTaskInput {
  orgId: string;
  projectId: string;
  assigneeUserId?: string | null;
  title: string;
  description?: string;
  status?: string;
  priority?: string;
  storyPoints?: number | null;
  dueDate?: string | null;
}

export function createTask(db: Database, input: CreateTaskInput) {
  const now = new Date().toISOString();
  const id = `task_${Math.random().toString(36).slice(2, 10)}`;

  db.query(`
    INSERT INTO tasks (
      id, org_id, project_id, assignee_user_id, title, description, status, priority, story_points, due_date, created_at, updated_at
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `).run(
    id,
    input.orgId,
    input.projectId,
    input.assigneeUserId ?? null,
    input.title,
    input.description ?? "",
    input.status ?? "todo",
    input.priority ?? "medium",
    input.storyPoints ?? null,
    input.dueDate ?? null,
    now,
    now,
  );

  return getTaskDetail(db, id);
}

export interface UpdateTaskInput {
  title?: string;
  description?: string;
  status?: string;
  priority?: string;
  assigneeUserId?: string | null;
  storyPoints?: number | null;
  dueDate?: string | null;
}

export function updateTask(db: Database, taskId: string, input: UpdateTaskInput) {
  const existing = db.query("SELECT id FROM tasks WHERE id = ?").get(taskId);
  if (!existing) {
    return null;
  }

  const fields: string[] = [];
  const values: Array<string | number | null> = [];

  if (input.title !== undefined) {
    fields.push("title = ?");
    values.push(input.title);
  }
  if (input.description !== undefined) {
    fields.push("description = ?");
    values.push(input.description);
  }
  if (input.status !== undefined) {
    fields.push("status = ?");
    values.push(input.status);
  }
  if (input.priority !== undefined) {
    fields.push("priority = ?");
    values.push(input.priority);
  }
  if (input.assigneeUserId !== undefined) {
    fields.push("assignee_user_id = ?");
    values.push(input.assigneeUserId);
  }
  if (input.storyPoints !== undefined) {
    fields.push("story_points = ?");
    values.push(input.storyPoints);
  }
  if (input.dueDate !== undefined) {
    fields.push("due_date = ?");
    values.push(input.dueDate);
  }

  fields.push("updated_at = ?");
  values.push(new Date().toISOString());
  values.push(taskId);

  db.query(`UPDATE tasks SET ${fields.join(", ")} WHERE id = ?`).run(...values);
  return getTaskDetail(db, taskId);
}
