/**
 * LysnrAI MCP tools — lysnrai.transcripts.*, lysnrai.stt.*, lysnrai.sessions.*,
 * lysnrai.orgs.*, lysnrai.apiTokens.*
 *
 * Backed by: lysnrai-backend (port 4015).
 * All tools require admin role.
 */

import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import { config } from '../../lib/config.js';
import {
  lysnraiTranscriptsList,
  lysnraiTranscriptGet,
  lysnraiTranscriptRunExtraction,
  lysnraiSttGetBackendStatus,
  lysnraiSessionGet,
  lysnraiSessionsList,
  lysnraiOrgsList,
  lysnraiOrgGet,
  lysnraiApiTokensList,
  lysnraiApiTokenCreate,
  lysnraiApiTokenRevoke,
  lysnraiSessionsStats,
  lysnraiTranscriptsExportBatch,
} from '../../lib/lysnrai-client.js';
import type { McpToolRequest } from '../tools/types.js';

const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7);

// ── lysnrai.transcripts.get ───────────────────────────────────────────────

registerTool({
  name: 'lysnrai.transcripts.get',
  description:
    'Get a single transcript by ID, including extractions[] and extractionMetadata if extraction has run. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    transcriptId: z.string().min(1).describe('Transcript ID'),
  }),
  async execute(args, req) {
    return lysnraiTranscriptGet(args.transcriptId, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.transcripts.list ──────────────────────────────────────────────

registerTool({
  name: 'lysnrai.transcripts.list',
  description: 'List dictation transcripts for the authenticated user. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
    offset: z.coerce.number().min(0).default(0),
  }),
  async execute(args, req) {
    return lysnraiTranscriptsList(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.transcripts.runExtraction ────────────────────────────────────

registerTool({
  name: 'lysnrai.transcripts.runExtraction',
  description:
    'Run extraction-service enrichment on a transcript — populates extractions[] and extractedAt. Best-effort: returns partial if extraction-service is unavailable. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    transcriptId: z.string().min(1).describe('Transcript ID (trx_... prefix)'),
  }),
  async execute(args, req) {
    return lysnraiTranscriptRunExtraction(args.transcriptId, {
      token: tokenOf(req),
      requestId: req.id,
    });
  },
});

// ── lysnrai.stt.getBackendStatus ──────────────────────────────────────────

registerTool({
  name: 'lysnrai.stt.getBackendStatus',
  description:
    'Report which speech-to-text backend is active: azure (Azure Speech SDK) or whisper (local Whisper model). Useful for ops health checks. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return lysnraiSttGetBackendStatus({ token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.sessions.get ──────────────────────────────────────────────────

registerTool({
  name: 'lysnrai.sessions.get',
  description:
    'Get a single dictation session by ID including its entries[], composedText, compositionHistory, and status. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    sessionId: z.string().min(1).describe('Session ID (ses_… prefix)'),
  }),
  async execute(args, req) {
    return lysnraiSessionGet(args.sessionId, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.sessions.list ─────────────────────────────────────────────────

registerTool({
  name: 'lysnrai.sessions.list',
  description: 'List dictation sessions for the authenticated user. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    status: z
      .enum(['active', 'composed', 'archived'])
      .optional()
      .describe('Filter by session status'),
    limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
    offset: z.coerce.number().min(0).default(0),
  }),
  async execute(args, req) {
    return lysnraiSessionsList(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.orgs.list ─────────────────────────────────────────────────────

registerTool({
  name: 'lysnrai.orgs.list',
  description: 'List organisations for the authenticated user. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
    offset: z.coerce.number().min(0).default(0),
  }),
  async execute(args, req) {
    return lysnraiOrgsList(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.orgs.get ─────────────────────────────────────────────────────

registerTool({
  name: 'lysnrai.orgs.get',
  description:
    'Get a single organisation by ID including member count, vocabulary, and shared instructions. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    orgId: z.string().min(1).describe('Organisation ID'),
  }),
  async execute(args, req) {
    return lysnraiOrgGet(args.orgId, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.apiTokens.revoke ───────────────────────────────────────────────

registerTool({
  name: 'lysnrai.apiTokens.revoke',
  description:
    'Revoke (soft-delete) an API token by ID — sets status to "revoked" so it can no longer authenticate. Irreversible. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    tokenId: z.string().min(1).describe('API token ID (tok_… prefix)'),
  }),
  async execute(args, req) {
    return lysnraiApiTokenRevoke(args.tokenId, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.apiTokens.list ─────────────────────────────────────────────────

registerTool({
  name: 'lysnrai.apiTokens.list',
  description: 'List API tokens for the authenticated user. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
    offset: z.coerce.number().min(0).default(0),
  }),
  async execute(args, req) {
    return lysnraiApiTokensList(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.sessions.stats ────────────────────────────────────────────────

registerTool({
  name: 'lysnrai.sessions.stats',
  description:
    'Get aggregated dictation session statistics for the authenticated user: total sessions, composed count, average word count, and last session date. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({}),
  async execute(_args, req) {
    return lysnraiSessionsStats({ token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.transcripts.exportBatch ──────────────────────────────────────

registerTool({
  name: 'lysnrai.transcripts.exportBatch',
  description:
    'Batch-export transcripts for the authenticated user as JSON or plain text. Returns a signed export URL, item count, and format. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    format: z.enum(['json', 'txt']).default('json').describe('Export format'),
    limit: z.coerce
      .number()
      .min(1)
      .max(config.QUERY_MAX_LIMIT)
      .default(config.QUERY_DEFAULT_LIMIT)
      .describe('Max transcripts to include'),
  }),
  async execute(args, req) {
    return lysnraiTranscriptsExportBatch(args, { token: tokenOf(req), requestId: req.id });
  },
});

// ── lysnrai.apiTokens.rotate ──────────────────────────────────────────────

registerTool({
  name: 'lysnrai.apiTokens.rotate',
  description:
    'Rotate an API token: revokes the existing token and issues a fresh one with the same name. Returns the new raw token (shown once only). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    tokenId: z.string().min(1).describe('Existing API token ID to rotate'),
    name: z.string().min(1).describe('Name for the replacement token'),
  }),
  async execute(args, req) {
    const opts = { token: tokenOf(req), requestId: req.id };
    await lysnraiApiTokenRevoke(args.tokenId, opts);
    return lysnraiApiTokenCreate({ name: args.name }, opts);
  },
});
