import type { ToolDef } from '../../llm/openai-compat.js';
import type { ToolContext, ToolResult } from './core.js';
import type { Repository } from '../../db/repository.js';

const SLUG_PATTERN = /^[a-z0-9-]+$/;
const MAX_SLUG_LEN = 32;
const MAX_TITLE_LEN = 64;
const MAX_CONTENT_BYTES = 64 * 1024;

let _repo: Repository | null = null;

export function setDashboardRepo(repo: Repository | null): void {
  _repo = repo;
}

const UPDATE_DASHBOARD_WIDGET_DEF: ToolDef = {
  type: 'function',
  function: {
    name: 'UpdateDashboardWidget',
    description: 'ユーザーの個人ダッシュボード Markdown widget を upsert する（既存 slug は更新、未存在は新規作成）。詳細は ReadToolDoc({ name: "UpdateDashboardWidget" })。',
    parameters: {
      type: 'object',
      properties: {
        slug: {
          type: 'string',
          description: 'Widget の安定 ID。kebab-case、a-z 0-9 ハイフンのみ、32 文字以内（例: memo, news, todo）',
        },
        content: {
          type: 'string',
          description: 'Markdown 本文。64KB まで',
        },
        title: {
          type: 'string',
          description: '表示タイトル。新規 slug では必須、既存 slug では無視',
        },
        mode: {
          type: 'string',
          enum: ['replace', 'append'],
          description: 'replace (default) | append (既存末尾に "\\n\\n" 区切りで追記)',
        },
      },
      required: ['slug', 'content'],
    },
  },
};

export const TOOL_DEFS: Record<string, ToolDef> = {
  UpdateDashboardWidget: UPDATE_DASHBOARD_WIDGET_DEF,
};

type ExecuteCtx = ToolContext & { ownerId?: string | null };

export async function executeTool(
  name: string,
  input: Record<string, unknown>,
  ctx: ToolContext,
): Promise<ToolResult | null> {
  if (name !== 'UpdateDashboardWidget') return null;
  return executeUpdateDashboardWidget(input, ctx as ExecuteCtx);
}

async function executeUpdateDashboardWidget(
  input: Record<string, unknown>,
  ctx: ExecuteCtx,
): Promise<ToolResult> {
  if (!_repo) {
    return { output: 'Dashboard repo is not initialized', isError: true };
  }
  const userId = ctx.ownerId;
  if (!userId) {
    return { output: 'ownerId not present in tool context — UpdateDashboardWidget requires an authenticated task owner', isError: true };
  }
  const slug = input['slug'];
  const content = input['content'];
  const title = input['title'];
  const mode = input['mode'];

  if (typeof slug !== 'string' || !SLUG_PATTERN.test(slug) || slug.length > MAX_SLUG_LEN) {
    return { output: `invalid slug: must match ${SLUG_PATTERN} and be <= ${MAX_SLUG_LEN} chars`, isError: true };
  }
  if (typeof content !== 'string') {
    return { output: 'content must be string', isError: true };
  }
  if (Buffer.byteLength(content, 'utf8') > MAX_CONTENT_BYTES) {
    return { output: `content exceeds size limit (${MAX_CONTENT_BYTES} bytes / 64KB)`, isError: true };
  }
  if (mode !== undefined && mode !== 'replace' && mode !== 'append') {
    return { output: 'mode must be "replace" or "append"', isError: true };
  }
  if (title !== undefined && (typeof title !== 'string' || title.length === 0 || title.length > MAX_TITLE_LEN)) {
    return { output: `title must be a non-empty string up to ${MAX_TITLE_LEN} chars`, isError: true };
  }

  const existing = (await _repo.listDashboardWidgets(userId)).find(w => w.slug === slug);
  if (!existing && (typeof title !== 'string' || title.length === 0)) {
    return { output: `slug "${slug}" does not exist yet — title is required when creating a new widget`, isError: true };
  }

  try {
    const widget = await _repo.upsertDashboardWidgetBySlug({
      userId,
      slug,
      title: typeof title === 'string' ? title : undefined,
      content,
      mode: mode === 'append' ? 'append' : 'replace',
    });
    const verb = existing ? (mode === 'append' ? 'appended to' : 'updated') : 'created';
    return {
      output: `Widget "${slug}" ${verb} (id=${widget.id}, ${Buffer.byteLength(widget.markdownContent, 'utf8')} bytes)`,
      isError: false,
    };
  } catch (e) {
    return { output: `Failed to update widget: ${(e as Error).message}`, isError: true };
  }
}
