import { google } from 'googleapis';
import type { GtasksConfig } from '../../config/schema.js';
import { createGoogleOAuth2Client } from '../../google/oauth.js';
import type { Tool, ToolResult } from '../types.js';

function createOAuth2Client(config: NonNullable<GtasksConfig>) {
  return createGoogleOAuth2Client({
    service: 'gtasks',
    credentialsFile: config.credentials_file,
    tokenFile: config.token_file,
  });
}

interface TaskListSummary {
  id: string;
  title: string;
  updated: string;
}

interface TaskSummary {
  id: string;
  title: string;
  status: string;
  due: string;
  notes: string;
  updated: string;
  parent: string;
}

/** Format task lists for tool output. */
function formatTaskLists(lists: TaskListSummary[]): string {
  if (lists.length === 0) {
    return 'No task lists found.';
  }

  return lists
    .map(l => `[${l.id}] ${l.title}\n  Updated: ${l.updated}`)
    .join('\n\n');
}

/** Format tasks for tool output. */
function formatTasks(tasks: TaskSummary[]): string {
  if (tasks.length === 0) {
    return 'No tasks found.';
  }

  return tasks
    .map(t => {
      const checkbox = t.status === 'completed' ? '[x]' : '[ ]';
      const parts = [`${checkbox} ${t.title}`];
      if (t.due) {parts.push(`  Due: ${t.due}`);}
      if (t.notes) {parts.push(`  Notes: ${t.notes}`);}
      parts.push(`  ID: ${t.id}`);
      return parts.join('\n');
    })
    .join('\n\n');
}

function parseErrorMessage(error: unknown): string {
  if (error instanceof Error) {
    return error.message;
  }
  return String(error);
}

function formatToolError(message: string): string {
  const needsScopeHint = /insufficient.*scope|insufficientPermissions|Request had insufficient authentication scopes/i.test(message);
  return needsScopeHint
    ? `${message}. Re-run "flynn gtasks-auth" to grant Google Tasks read permissions.`
    : message;
}

/**
 * Creates Google Tasks read-only tools bound to the given GtasksConfig.
 * Tools create their own OAuth2 client per invocation.
 */
export function createGtasksTools(config: NonNullable<GtasksConfig>): Tool[] {
  const tasksLists: Tool = {
    name: 'tasks.lists',
    description:
      'List all Google Tasks task lists. Returns id, title, and last updated time for each list.',
    requiredSecretScopes: ['gtasks'],
    inputSchema: {
      type: 'object',
      properties: {
        maxResults: {
          type: 'number',
          description: 'Maximum number of task lists to return (default: 20)',
        },
      },
    },
    execute: async (rawArgs: unknown): Promise<ToolResult> => {
      const args = rawArgs as { maxResults?: number };
      const maxResults = args.maxResults ?? 20;

      try {
        const auth = createOAuth2Client(config);
        const tasks = google.tasks({ version: 'v1', auth });

        const response = await tasks.tasklists.list({
          maxResults,
        });

        const items = response.data.items ?? [];
        const lists: TaskListSummary[] = items.map(l => ({
          id: l.id ?? '',
          title: l.title ?? '(untitled)',
          updated: l.updated ?? '',
        }));

        return {
          success: true,
          output: formatTaskLists(lists),
        };
      } catch (error) {
        const message = parseErrorMessage(error);
        return {
          success: false,
          output: '',
          error: formatToolError(message),
        };
      }
    },
  };

  const tasksList: Tool = {
    name: 'tasks.list',
    description:
      'List tasks from a Google Tasks task list. Returns title, status (completed/needsAction), due date, and notes. Use tasks.lists first to get task list IDs.',
    requiredSecretScopes: ['gtasks'],
    inputSchema: {
      type: 'object',
      properties: {
        taskListId: {
          type: 'string',
          description: 'Task list ID (from tasks.lists). Defaults to the primary "@default" list.',
        },
        maxResults: {
          type: 'number',
          description: 'Maximum number of tasks to return (default: 100)',
        },
        showCompleted: {
          type: 'boolean',
          description: 'Whether to include completed tasks (default: true)',
        },
        showHidden: {
          type: 'boolean',
          description: 'Whether to include hidden/deleted tasks (default: false)',
        },
      },
    },
    execute: async (rawArgs: unknown): Promise<ToolResult> => {
      const args = rawArgs as { taskListId?: string; maxResults?: number; showCompleted?: boolean; showHidden?: boolean };
      const taskListId = args.taskListId ?? '@default';
      const maxResults = args.maxResults ?? 100;

      try {
        const auth = createOAuth2Client(config);
        const tasks = google.tasks({ version: 'v1', auth });

        const response = await tasks.tasks.list({
          tasklist: taskListId,
          maxResults,
          showCompleted: args.showCompleted ?? true,
          showHidden: args.showHidden ?? false,
        });

        const items = response.data.items ?? [];
        const taskList: TaskSummary[] = items.map(t => ({
          id: t.id ?? '',
          title: t.title ?? '(untitled)',
          status: t.status ?? 'needsAction',
          due: t.due ?? '',
          notes: t.notes ?? '',
          updated: t.updated ?? '',
          parent: t.parent ?? '',
        }));

        return {
          success: true,
          output: formatTasks(taskList),
        };
      } catch (error) {
        const message = parseErrorMessage(error);
        return {
          success: false,
          output: '',
          error: formatToolError(message),
        };
      }
    },
  };

  return [tasksLists, tasksList];
}
