import { JSONSchema7 } from 'json-schema';
import { randomUUID } from 'crypto';
import { createTool, createSuccessResult, createErrorResult } from '../../core/tool-framework.js';
import { ToolRegistration, RequestContext } from '../../core/types.js';
import { renderADRTemplate } from './templates.js';
import type { ADR, ADRStatus } from './types.js';

/**
 * ADR Management Tools - 12-Factor MCP Implementation
 * 
 * Implements Factor 2: Deterministic Execution with structured outputs
 * Implements Factor 3: Stateless Processes with RequestContext  
 * Implements Factor 4: Structured Outputs for LLM consumption
 */

// Input type interfaces
interface CreateADRInput {
  title: string;
  template?: 'nygard' | 'madr' | 'y-statement';
  deciders: string[];
  context: string;
  decision: string;
  consequences: string;
  tags?: string[];
  decisionDrivers?: string[];
  consideredOptions?: Array<{
    title: string;
    description: string;
    pros: string[];
    cons: string[];
  }>;
  prosAndCons?: Array<{
    option: string;
    pros: string[];
    cons: string[];
  }>;
  supersedes?: string[];
  relatedTo?: string[];
}

interface UpdateADRInput {
  id: string;
  status?: 'proposed' | 'accepted' | 'rejected' | 'deprecated' | 'superseded';
  statusChangeReason?: string;
  statusChangedBy?: string;
  title?: string;
  consequences?: string;
  tags?: string[];
  supersedes?: string[];
  supersededBy?: string;
  relatedTo?: string[];
  decisionDrivers?: string[];
  consideredOptions?: Array<{
    title: string;
    description: string;
    pros: string[];
    cons: string[];
  }>;
  prosAndCons?: Array<{
    option: string;
    pros: string[];
    cons: string[];
  }>;
}

interface GetADRInput {
  id: string;
}

interface ListADRsInput {
  status?: 'proposed' | 'accepted' | 'rejected' | 'deprecated' | 'superseded';
}

interface SearchADRsInput {
  query?: string;
  status?: string[];
  tags?: string[];
  template?: 'nygard' | 'madr' | 'y-statement';
  dateRange?: {
    from: string;
    to: string;
  };
  deciders?: string[];
}

interface LinkADRsInput {
  fromId: string;
  toId: string;
  relationship?: 'related-to' | 'supersedes';
}

interface DeleteADRInput {
  id: string;
}

/**
 * Generate next ADR number
 */
async function getNextADRNumber(context: RequestContext): Promise<string> {
  const result = await context.db.get(
    'SELECT MAX(CAST(SUBSTR(id, 5) AS INTEGER)) as max_num FROM adr_records WHERE project_id = ?',
    [context.projectId || 'default']
  );
  
  const nextNum = (result.data?.max_num || 0) + 1;
  return nextNum.toString().padStart(4, '0');
}

/**
 * Create a new Architecture Decision Record
 */
const createADRTool = createTool<CreateADRInput, any>({
  name: 'create_adr',
  description: 'Create a new Architecture Decision Record',
  category: 'adr',
  inputSchema: {
    type: 'object',
    properties: {
      title: {
        type: 'string',
        description: 'Title of the decision',
        minLength: 1,
        maxLength: 200
      },
      template: {
        type: 'string',
        enum: ['nygard', 'madr', 'y-statement'],
        default: 'nygard',
        description: 'ADR template to use'
      },
      deciders: {
        type: 'array',
        items: { type: 'string', minLength: 1, maxLength: 100 },
        description: 'People involved in the decision',
        minItems: 1,
        maxItems: 20
      },
      context: {
        type: 'string',
        description: 'Context and problem statement',
        minLength: 1,
        maxLength: 5000
      },
      decision: {
        type: 'string',
        description: 'The decision that was made',
        minLength: 1,
        maxLength: 5000
      },
      consequences: {
        type: 'string',
        description: 'Positive and negative consequences',
        minLength: 1,
        maxLength: 5000
      },
      tags: {
        type: 'array',
        items: { type: 'string', maxLength: 50 },
        description: 'Optional tags for categorization',
        maxItems: 20
      },
      decisionDrivers: {
        type: 'array',
        items: { type: 'string' },
        description: 'Key factors that influenced the decision (MADR template)',
        maxItems: 20
      },
      consideredOptions: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            title: { type: 'string', maxLength: 200 },
            description: { type: 'string', maxLength: 1000 },
            pros: { type: 'array', items: { type: 'string' } },
            cons: { type: 'array', items: { type: 'string' } }
          },
          required: ['title', 'description', 'pros', 'cons']
        },
        description: 'Alternative options that were considered (MADR template)',
        maxItems: 10
      },
      supersedes: {
        type: 'array',
        items: { type: 'string', pattern: '^ADR-\\d{4}$' },
        description: 'ADR IDs that this decision supersedes',
        maxItems: 10
      },
      relatedTo: {
        type: 'array',
        items: { type: 'string', pattern: '^ADR-\\d{4}$' },
        description: 'ADR IDs that this decision relates to',
        maxItems: 20
      }
    },
    required: ['title', 'deciders', 'context', 'decision', 'consequences'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CreateADRInput, context: RequestContext) {
    try {
      const adrNumber = await getNextADRNumber(context);
      const adrId = `ADR-${adrNumber}`;
      const now = Date.now();

      // Validate superseded ADRs exist
      if (input.supersedes) {
        for (const supersededId of input.supersedes) {
          const existsResult = await context.db.get(
            'SELECT id FROM adr_records WHERE id = ? AND project_id = ?',
            [supersededId, context.projectId || 'default']
          );
          
          if (!existsResult.success || !existsResult.data) {
            return createErrorResult({
              code: 'RESOURCE_NOT_FOUND',
              message: `Referenced ADR ${supersededId} not found`,
              category: 'validation'
            });
          }
        }
      }

      // Validate related ADRs exist
      if (input.relatedTo) {
        for (const relatedId of input.relatedTo) {
          const existsResult = await context.db.get(
            'SELECT id FROM adr_records WHERE id = ? AND project_id = ?',
            [relatedId, context.projectId || 'default']
          );
          
          if (!existsResult.success || !existsResult.data) {
            return createErrorResult({
              code: 'RESOURCE_NOT_FOUND',
              message: `Referenced ADR ${relatedId} not found`,
              category: 'validation'
            });
          }
        }
      }

      // Create ADR record in database
      const result = await context.db.run(
        `INSERT INTO adr_records 
         (id, title, status, date, deciders, template, context, decision, consequences, 
          tags, decision_drivers, considered_options, pros_and_cons, supersedes, 
          superseded_by, related_to, project_id, created_at, updated_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          adrId,
          input.title,
          'proposed',
          now,
          JSON.stringify(input.deciders),
          input.template || 'nygard',
          input.context,
          input.decision,
          input.consequences,
          JSON.stringify(input.tags || []),
          JSON.stringify(input.decisionDrivers || []),
          JSON.stringify(input.consideredOptions || []),
          JSON.stringify(input.prosAndCons || []),
          JSON.stringify(input.supersedes || []),
          null,
          JSON.stringify(input.relatedTo || []),
          context.projectId || 'default',
          now,
          now
        ]
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to create ADR',
          details: { error: result.error },
          category: 'system'
        });
      }

      // Update superseded ADRs
      if (input.supersedes) {
        for (const supersededId of input.supersedes) {
          await context.db.run(
            'UPDATE adr_records SET status = ?, superseded_by = ?, updated_at = ? WHERE id = ? AND project_id = ?',
            ['superseded', adrId, now, supersededId, context.projectId || 'default']
          );
        }
      }

      // Create status history entry
      await context.db.run(
        `INSERT INTO adr_status_history 
         (id, adr_id, from_status, to_status, changed_at, changed_by, reason, project_id) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
        [randomUUID(), adrId, null, 'proposed', now, context.userId || 'system', 'Initial creation', context.projectId || 'default']
      );

      // Build ADR object for template rendering
      const adr: ADR = {
        id: adrId,
        title: input.title,
        status: 'proposed' as ADRStatus,
        date: new Date(now),
        deciders: input.deciders,
        template: input.template || 'nygard',
        context: input.context,
        decision: input.decision,
        consequences: input.consequences,
        tags: input.tags,
        decisionDrivers: input.decisionDrivers,
        consideredOptions: input.consideredOptions,
        prosAndCons: input.prosAndCons,
        supersedes: input.supersedes,
        relatedTo: input.relatedTo,
        createdAt: new Date(now),
        updatedAt: new Date(now),
        statusHistory: []
      };

      const markdown = renderADRTemplate(adr);

      return createSuccessResult({
        adr: {
          id: adrId,
          title: input.title,
          status: 'proposed',
          template: input.template || 'nygard',
          deciders: input.deciders,
          createdAt: new Date(now).toISOString()
        },
        markdown,
        message: `ADR ${adrId} "${input.title}" created successfully`,
        nextSteps: [
          'Review the decision with stakeholders',
          'Update status when decision is finalized',
          'Link to related ADRs if needed'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to create ADR: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Update an existing ADR
 */
const updateADRTool = createTool<UpdateADRInput, any>({
  name: 'update_adr',
  description: 'Update an existing Architecture Decision Record',
  category: 'adr',
  inputSchema: {
    type: 'object',
    properties: {
      id: {
        type: 'string',
        description: 'ADR ID (e.g., ADR-0001)',
        pattern: '^ADR-\\d{4}$'
      },
      status: {
        type: 'string',
        enum: ['proposed', 'accepted', 'rejected', 'deprecated', 'superseded'],
        description: 'New status'
      },
      statusChangeReason: {
        type: 'string',
        description: 'Reason for status change',
        maxLength: 1000
      },
      statusChangedBy: {
        type: 'string',
        description: 'Person making the status change',
        maxLength: 100
      },
      title: {
        type: 'string',
        description: 'Updated title',
        maxLength: 200
      },
      consequences: {
        type: 'string',
        description: 'Updated consequences',
        maxLength: 5000
      },
      tags: {
        type: 'array',
        items: { type: 'string', maxLength: 50 },
        description: 'Updated tags',
        maxItems: 20
      }
    },
    required: ['id'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: UpdateADRInput, context: RequestContext) {
    try {
      // Get existing ADR
      const adrResult = await context.db.get(
        'SELECT * FROM adr_records WHERE id = ? AND project_id = ?',
        [input.id, context.projectId || 'default']
      );

      if (!adrResult.success || !adrResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: `ADR ${input.id} not found`,
          category: 'validation'
        });
      }

      const existingADR = adrResult.data;
      const now = Date.now();
      const updates: string[] = [];
      const values: any[] = [];

      // Build update query dynamically
      if (input.title !== undefined) {
        updates.push('title = ?');
        values.push(input.title);
      }

      if (input.consequences !== undefined) {
        updates.push('consequences = ?');
        values.push(input.consequences);
      }

      if (input.tags !== undefined) {
        updates.push('tags = ?');
        values.push(JSON.stringify(input.tags));
      }

      if (input.status !== undefined && input.status !== existingADR.status) {
        updates.push('status = ?');
        values.push(input.status);

        // Record status change
        await context.db.run(
          `INSERT INTO adr_status_history 
           (id, adr_id, from_status, to_status, changed_at, changed_by, reason, project_id) 
           VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            randomUUID(),
            input.id,
            existingADR.status,
            input.status,
            now,
            input.statusChangedBy || context.userId || 'unknown',
            input.statusChangeReason || null,
            context.projectId || 'default'
          ]
        );
      }

      if (updates.length > 0) {
        updates.push('updated_at = ?');
        values.push(now);
        values.push(input.id);
        values.push(context.projectId || 'default');

        const updateResult = await context.db.run(
          `UPDATE adr_records SET ${updates.join(', ')} WHERE id = ? AND project_id = ?`,
          values
        );

        if (!updateResult.success) {
          return createErrorResult({
            code: 'DATABASE_ERROR',
            message: 'Failed to update ADR',
            details: { error: updateResult.error },
            category: 'system'
          });
        }
      }

      // Get updated ADR with status history
      const updatedResult = await context.db.get(
        'SELECT * FROM adr_records WHERE id = ? AND project_id = ?',
        [input.id, context.projectId || 'default']
      );

      const historyResult = await context.db.query(
        'SELECT * FROM adr_status_history WHERE adr_id = ? AND project_id = ? ORDER BY changed_at',
        [input.id, context.projectId || 'default']
      );

      const statusHistory = (historyResult.data || []).map((h: any) => ({
        from: h.from_status,
        to: h.to_status,
        date: new Date(h.changed_at).toISOString(),
        changedBy: h.changed_by,
        reason: h.reason
      }));

      return createSuccessResult({
        adr: {
          id: input.id,
          title: updatedResult.data?.title,
          status: updatedResult.data?.status,
          updatedAt: new Date(updatedResult.data?.updated_at || now).toISOString()
        },
        statusHistory,
        message: `ADR ${input.id} updated successfully`,
        changesApplied: updates.length > 0 ? updates.map(u => u.split(' = ')[0]) : ['No changes']
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to update ADR: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Get a specific ADR
 */
const getADRTool = createTool<GetADRInput, any>({
  name: 'get_adr',
  description: 'Get details of a specific Architecture Decision Record',
  category: 'adr',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      id: {
        type: 'string',
        description: 'ADR ID (e.g., ADR-0001)',
        pattern: '^ADR-\\d{4}$'
      }
    },
    required: ['id'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: GetADRInput, context: RequestContext) {
    try {
      // Get ADR details
      const adrResult = await context.db.get(
        'SELECT * FROM adr_records WHERE id = ? AND project_id = ?',
        [input.id, context.projectId || 'default']
      );

      if (!adrResult.success || !adrResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: `ADR ${input.id} not found`,
          category: 'validation'
        });
      }

      const adr = adrResult.data;

      // Get status history
      const historyResult = await context.db.query(
        'SELECT * FROM adr_status_history WHERE adr_id = ? AND project_id = ? ORDER BY changed_at',
        [input.id, context.projectId || 'default']
      );

      // Build full ADR object for template rendering
      const adrObject = {
        id: adr.id,
        title: adr.title,
        status: adr.status,
        date: new Date(adr.date),
        deciders: JSON.parse(adr.deciders || '[]'),
        template: adr.template,
        context: adr.context,
        decision: adr.decision,
        consequences: adr.consequences,
        tags: JSON.parse(adr.tags || '[]'),
        decisionDrivers: JSON.parse(adr.decision_drivers || '[]'),
        consideredOptions: JSON.parse(adr.considered_options || '[]'),
        prosAndCons: JSON.parse(adr.pros_and_cons || '[]'),
        supersedes: JSON.parse(adr.supersedes || '[]'),
        supersededBy: adr.superseded_by,
        relatedTo: JSON.parse(adr.related_to || '[]'),
        createdAt: new Date(adr.created_at),
        updatedAt: new Date(adr.updated_at),
        statusHistory: (historyResult.data || []).map((h: any) => ({
          from: h.from_status,
          to: h.to_status,
          date: new Date(h.changed_at),
          changedBy: h.changed_by,
          reason: h.reason
        }))
      };

      const markdown = renderADRTemplate(adrObject);

      // Build relationships
      const relationships = [];
      if (adrObject.relatedTo) {
        for (const relatedId of adrObject.relatedTo) {
          relationships.push({ type: 'related-to', from: input.id, to: relatedId });
        }
      }
      if (adrObject.supersedes) {
        for (const supersededId of adrObject.supersedes) {
          relationships.push({ type: 'supersedes', from: input.id, to: supersededId });
        }
      }
      if (adrObject.supersededBy) {
        relationships.push({ type: 'superseded-by', from: input.id, to: adrObject.supersededBy });
      }

      return createSuccessResult({
        adr: adrObject,
        markdown,
        relationships,
        statusHistory: adrObject.statusHistory
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to get ADR: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * List all ADRs with optional filtering
 */
const listADRsTool = createTool<ListADRsInput, any>({
  name: 'list_adrs',
  description: 'List all Architecture Decision Records with optional status filter',
  category: 'adr',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      status: {
        type: 'string',
        enum: ['proposed', 'accepted', 'rejected', 'deprecated', 'superseded'],
        description: 'Filter by status'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ListADRsInput, context: RequestContext) {
    try {
      let query = 'SELECT id, title, status, date, deciders, tags, created_at FROM adr_records WHERE project_id = ?';
      const params = [context.projectId || 'default'];

      if (input.status) {
        query += ' AND status = ?';
        params.push(input.status);
      }

      query += ' ORDER BY date DESC';

      const result = await context.db.query(query, params);

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to list ADRs',
          details: { error: result.error },
          category: 'system'
        });
      }

      const adrs = (result.data || []).map((adr: any) => ({
        id: adr.id,
        title: adr.title,
        status: adr.status,
        date: new Date(adr.date).toISOString(),
        deciders: JSON.parse(adr.deciders || '[]'),
        tags: JSON.parse(adr.tags || '[]'),
        createdAt: new Date(adr.created_at).toISOString()
      }));

      return createSuccessResult({
        adrs,
        count: adrs.length,
        filter: input.status ? { status: input.status } : null
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to list ADRs: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Delete an ADR
 */
const deleteADRTool = createTool<DeleteADRInput, any>({
  name: 'delete_adr',
  description: 'Delete an Architecture Decision Record',
  category: 'adr',
  inputSchema: {
    type: 'object',
    properties: {
      id: {
        type: 'string',
        description: 'ADR ID to delete',
        pattern: '^ADR-\\d{4}$'
      }
    },
    required: ['id'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: DeleteADRInput, context: RequestContext) {
    try {
      // Check if ADR exists
      const existsResult = await context.db.get(
        'SELECT id, title FROM adr_records WHERE id = ? AND project_id = ?',
        [input.id, context.projectId || 'default']
      );

      if (!existsResult.success || !existsResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: `ADR ${input.id} not found`,
          category: 'validation'
        });
      }

      const adr = existsResult.data;

      // Delete in transaction to ensure consistency
      await context.db.transaction(async (tx) => {
        // Delete status history
        await tx.run(
          'DELETE FROM adr_status_history WHERE adr_id = ? AND project_id = ?',
          [input.id, context.projectId || 'default']
        );

        // Delete the ADR
        await tx.run(
          'DELETE FROM adr_records WHERE id = ? AND project_id = ?',
          [input.id, context.projectId || 'default']
        );

        // Update any ADRs that reference this one
        await tx.run(
          'UPDATE adr_records SET superseded_by = NULL WHERE superseded_by = ? AND project_id = ?',
          [input.id, context.projectId || 'default']
        );
      });

      return createSuccessResult({
        message: `ADR ${input.id} "${adr.title}" deleted successfully`,
        deletedADR: {
          id: input.id,
          title: adr.title
        }
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to delete ADR: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Get ADR metrics and statistics
 */
const getADRMetricsTool = createTool<{}, any>({
  name: 'adr_metrics',
  description: 'Get metrics and statistics about Architecture Decision Records',
  category: 'adr',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {},
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: {}, context: RequestContext) {
    try {
      // Get total count and status breakdown
      const statusResult = await context.db.query(
        'SELECT status, COUNT(*) as count FROM adr_records WHERE project_id = ? GROUP BY status',
        [context.projectId || 'default']
      );

      // Get template breakdown
      const templateResult = await context.db.query(
        'SELECT template, COUNT(*) as count FROM adr_records WHERE project_id = ? GROUP BY template',
        [context.projectId || 'default']
      );

      // Get total count
      const totalResult = await context.db.get(
        'SELECT COUNT(*) as total FROM adr_records WHERE project_id = ?',
        [context.projectId || 'default']
      );

      // Get most active deciders
      const decidersResult = await context.db.query(
        'SELECT deciders FROM adr_records WHERE project_id = ?',
        [context.projectId || 'default']
      );

      // Process deciders data
      const deciderCounts = new Map();
      (decidersResult.data || []).forEach((row: any) => {
        const deciders = JSON.parse(row.deciders || '[]');
        deciders.forEach((decider: string) => {
          deciderCounts.set(decider, (deciderCounts.get(decider) || 0) + 1);
        });
      });

      const mostActiveDeciders = Array.from(deciderCounts.entries())
        .map(([name, count]) => ({ name, count }))
        .sort((a, b) => b.count - a.count)
        .slice(0, 10);

      // Calculate average decision time for accepted ADRs
      const decisionTimeResult = await context.db.query(
        `SELECT adr.created_at, h.changed_at 
         FROM adr_records adr 
         JOIN adr_status_history h ON adr.id = h.adr_id 
         WHERE adr.project_id = ? AND h.to_status = 'accepted'`,
        [context.projectId || 'default']
      );

      let averageDecisionTime = 0;
      if (decisionTimeResult.data && decisionTimeResult.data.length > 0) {
        const decisionTimes = decisionTimeResult.data.map((row: any) => {
          return (row.changed_at - row.created_at) / (1000 * 60 * 60 * 24); // Convert to days
        });
        averageDecisionTime = decisionTimes.reduce((a: number, b: number) => a + b, 0) / decisionTimes.length;
      }

      // Build status breakdown
      const statusBreakdown: Record<string, number> = {
        proposed: 0,
        accepted: 0,
        rejected: 0,
        deprecated: 0,
        superseded: 0
      };

      (statusResult.data || []).forEach((row: any) => {
        statusBreakdown[row.status] = row.count;
      });

      // Build template breakdown
      const templateBreakdown: Record<string, number> = {
        nygard: 0,
        madr: 0,
        'y-statement': 0
      };

      (templateResult.data || []).forEach((row: any) => {
        templateBreakdown[row.template] = row.count;
      });

      return createSuccessResult({
        metrics: {
          total: totalResult.data?.total || 0,
          byStatus: statusBreakdown,
          byTemplate: templateBreakdown,
          averageDecisionTime: Math.round(averageDecisionTime * 100) / 100,
          mostActiveDeciders
        },
        insights: [
          `Total ${totalResult.data?.total || 0} ADRs in the system`,
          statusBreakdown.accepted > 0 ? `${statusBreakdown.accepted} decisions have been accepted` : 'No accepted decisions yet',
          averageDecisionTime > 0 ? `Average decision time: ${Math.round(averageDecisionTime * 100) / 100} days` : 'No decision time data available',
          mostActiveDeciders.length > 0 ? `Most active decider: ${mostActiveDeciders[0].name} (${mostActiveDeciders[0].count} decisions)` : 'No decision makers identified'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to get ADR metrics: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Create ADR interactively (placeholder - uses wizard)
 */
const createADRInteractiveTool = createTool<{}, any>({
  name: 'create_adr_interactive',
  description: 'Start interactive ADR creation process',
  category: 'adr',
  inputSchema: {
    type: 'object',
    properties: {},
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: {}, context: RequestContext) {
    return createSuccessResult({
      message: 'Interactive ADR creation started',
      instructions: [
        'Use create_adr tool with required fields:',
        '- title: Brief title of the decision',
        '- deciders: Array of decision makers',
        '- context: Situation context',
        '- decision: The decision made',
        '- consequences: Expected outcomes'
      ],
      nextStep: 'call_create_adr'
    });
  }
});

/**
 * Link ADRs with relationships
 */
const linkADRsTool = createTool<{ sourceId: string; targetId: string; relationship: string }, any>({
  name: 'link_adrs',
  description: 'Create relationships between ADRs',
  category: 'adr',
  inputSchema: {
    type: 'object',
    properties: {
      sourceId: {
        type: 'string',
        description: 'Source ADR ID',
        pattern: '^[a-zA-Z0-9-]+$'
      },
      targetId: {
        type: 'string',
        description: 'Target ADR ID', 
        pattern: '^[a-zA-Z0-9-]+$'
      },
      relationship: {
        type: 'string',
        enum: ['supersedes', 'relates_to', 'amends'],
        description: 'Type of relationship'
      }
    },
    required: ['sourceId', 'targetId', 'relationship'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: { sourceId: string; targetId: string; relationship: string }, context: RequestContext) {
    try {
      // Verify both ADRs exist
      const sourceResult = await context.db.get(
        'SELECT * FROM adr_records WHERE id = ? AND project_id = ?',
        [input.sourceId, context.projectId || 'default']
      );

      const targetResult = await context.db.get(
        'SELECT * FROM adr_records WHERE id = ? AND project_id = ?',
        [input.targetId, context.projectId || 'default']
      );

      if (!sourceResult.success || !sourceResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: 'Source ADR not found',
          details: { sourceId: input.sourceId },
          category: 'validation'
        });
      }

      if (!targetResult.success || !targetResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: 'Target ADR not found',
          details: { targetId: input.targetId },
          category: 'validation'
        });
      }

      // Update relationships based on type
      const now = new Date().toISOString();
      
      if (input.relationship === 'supersedes') {
        // Update source ADR to include supersedes
        const sourceSupersedes = JSON.parse(sourceResult.data.supersedes || '[]');
        if (!sourceSupersedes.includes(input.targetId)) {
          sourceSupersedes.push(input.targetId);
          await context.db.run(
            'UPDATE adr_records SET supersedes = ?, updated_at = ? WHERE id = ?',
            [JSON.stringify(sourceSupersedes), now, input.sourceId]
          );
        }

        // Update target ADR to be superseded by source
        await context.db.run(
          'UPDATE adr_records SET superseded_by = ?, status = ?, updated_at = ? WHERE id = ?',
          [input.sourceId, 'superseded', now, input.targetId]
        );
      } else {
        // For other relationships, update related_to field
        const sourceRelated = JSON.parse(sourceResult.data.related_to || '[]');
        if (!sourceRelated.includes(input.targetId)) {
          sourceRelated.push(input.targetId);
          await context.db.run(
            'UPDATE adr_records SET related_to = ?, updated_at = ? WHERE id = ?',
            [JSON.stringify(sourceRelated), now, input.sourceId]
          );
        }
      }

      return createSuccessResult({
        linked: true,
        relationship: input.relationship,
        source: sourceResult.data,
        target: targetResult.data
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to link ADRs: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Search ADRs
 */
const searchADRsTool = createTool<{ query?: string; startDate?: string; endDate?: string; status?: string }, any>({
  name: 'search_adrs',
  description: 'Search ADRs by content, date range, or status',
  category: 'adr',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      query: {
        type: 'string',
        description: 'Search query for title, context, or decision content',
        maxLength: 500
      },
      startDate: {
        type: 'string',
        format: 'date',
        description: 'Start date for search range'
      },
      endDate: {
        type: 'string', 
        format: 'date',
        description: 'End date for search range'
      },
      status: {
        type: 'string',
        enum: ['proposed', 'accepted', 'rejected', 'deprecated', 'superseded'],
        description: 'Filter by ADR status'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: { query?: string; startDate?: string; endDate?: string; status?: string }, context: RequestContext) {
    try {
      let sql = 'SELECT * FROM adr_records WHERE project_id = ?';
      const params: any[] = [context.projectId || 'default'];

      // Add text search
      if (input.query) {
        sql += ' AND (title LIKE ? OR context LIKE ? OR decision LIKE ?)';
        const searchTerm = `%${input.query}%`;
        params.push(searchTerm, searchTerm, searchTerm);
      }

      // Add date range
      if (input.startDate) {
        sql += ' AND created_at >= ?';
        params.push(input.startDate);
      }
      
      if (input.endDate) {
        sql += ' AND created_at <= ?';
        params.push(input.endDate + 'T23:59:59Z');
      }

      // Add status filter
      if (input.status) {
        sql += ' AND status = ?';
        params.push(input.status);
      }

      sql += ' ORDER BY created_at DESC';

      const result = await context.db.query(sql, params);

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to search ADRs',
          details: { error: result.error },
          category: 'system'
        });
      }

      const adrs = (result.data || []).map((row: any) => ({
        id: row.id,
        number: row.number,
        title: row.title,
        status: row.status,
        deciders: JSON.parse(row.deciders || '[]'),
        template: row.template,
        context: row.context,
        decision: row.decision,
        consequences: row.consequences,
        tags: JSON.parse(row.tags || '[]'),
        createdAt: new Date(row.created_at).toISOString(),
        updatedAt: new Date(row.updated_at).toISOString()
      }));

      return createSuccessResult({
        adrs,
        count: adrs.length,
        searchCriteria: {
          query: input.query || null,
          startDate: input.startDate || null,
          endDate: input.endDate || null,
          status: input.status || null
        }
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to search ADRs: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Validate ADR references
 */
const validateADRReferencesTool = createTool<{}, any>({
  name: 'validate_adr_references',
  description: 'Validate all ADR cross-references and relationships',
  category: 'adr',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {},
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: {}, context: RequestContext) {
    try {
      // Get all ADRs
      const result = await context.db.query(
        'SELECT * FROM adr_records WHERE project_id = ?',
        [context.projectId || 'default']
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to fetch ADRs for validation',
          category: 'system'
        });
      }

      const adrs = result.data || [];
      const adrIds = new Set(adrs.map((adr: any) => adr.id));
      const brokenReferences: string[] = [];
      const validReferences: string[] = [];

      // Check all references
      adrs.forEach((adr: any) => {
        const supersedes = JSON.parse(adr.supersedes || '[]');
        const relatedTo = JSON.parse(adr.related_to || '[]');
        
        // Check supersedes references
        supersedes.forEach((refId: string) => {
          if (!adrIds.has(refId)) {
            brokenReferences.push(`ADR ${adr.number} (${adr.id}) supersedes non-existent ADR ${refId}`);
          } else {
            validReferences.push(`ADR ${adr.number} supersedes reference is valid`);
          }
        });

        // Check related_to references
        relatedTo.forEach((refId: string) => {
          if (!adrIds.has(refId)) {
            brokenReferences.push(`ADR ${adr.number} (${adr.id}) relates to non-existent ADR ${refId}`);
          } else {
            validReferences.push(`ADR ${adr.number} related_to reference is valid`);
          }
        });

        // Check superseded_by references
        if (adr.superseded_by && !adrIds.has(adr.superseded_by)) {
          brokenReferences.push(`ADR ${adr.number} (${adr.id}) superseded by non-existent ADR ${adr.superseded_by}`);
        } else if (adr.superseded_by) {
          validReferences.push(`ADR ${adr.number} superseded_by reference is valid`);
        }
      });

      const isValid = brokenReferences.length === 0;

      return createSuccessResult({
        valid: isValid,
        totalReferences: validReferences.length + brokenReferences.length,
        validReferences: validReferences.length,
        brokenReferences: brokenReferences.length,
        issues: brokenReferences,
        summary: isValid 
          ? 'All ADR references are valid'
          : `Found ${brokenReferences.length} broken reference(s)`
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to validate ADR references: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Generate ADR decision log
 */
const generateADRLogTool = createTool<{ format?: 'markdown' | 'json' | 'csv' }, any>({
  name: 'generate_adr_log',
  description: 'Generate a comprehensive log of all architectural decisions',
  category: 'adr',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      format: {
        type: 'string',
        enum: ['markdown', 'json', 'csv'],
        default: 'markdown',
        description: 'Output format for the decision log'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: { format?: 'markdown' | 'json' | 'csv' }, context: RequestContext) {
    try {
      const result = await context.db.query(
        'SELECT * FROM adr_records WHERE project_id = ? ORDER BY number ASC',
        [context.projectId || 'default']
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to fetch ADRs for log generation',
          category: 'system'
        });
      }

      const adrs = result.data || [];
      const format = input.format || 'markdown';

      if (format === 'json') {
        return createSuccessResult({
          format: 'json',
          log: adrs.map((adr: any) => ({
            number: adr.number,
            title: adr.title,
            status: adr.status,
            deciders: JSON.parse(adr.deciders || '[]'),
            template: adr.template,
            context: adr.context,
            decision: adr.decision,
            consequences: adr.consequences,
            tags: JSON.parse(adr.tags || '[]'),
            supersedes: JSON.parse(adr.supersedes || '[]'),
            supersededBy: adr.superseded_by,
            relatedTo: JSON.parse(adr.related_to || '[]'),
            createdAt: adr.created_at,
            updatedAt: adr.updated_at
          }))
        });
      }

      if (format === 'csv') {
        const headers = 'Number,Title,Status,Deciders,Template,Created,Updated';
        const rows = adrs.map((adr: any) => {
          const deciders = JSON.parse(adr.deciders || '[]').join(';');
          return `${adr.number},"${adr.title}",${adr.status},"${deciders}",${adr.template},${adr.created_at},${adr.updated_at}`;
        });
        
        return createSuccessResult({
          format: 'csv',
          log: [headers, ...rows].join('\n')
        });
      }

      // Default markdown format
      const markdownLog = [
        '# Architecture Decision Log',
        '',
        `This log lists the architectural decisions for the project.`,
        '',
        '<!-- adrlog -->',
        '',
        ...adrs.map((adr: any) => {
          const deciders = JSON.parse(adr.deciders || '[]').join(', ');
          return `* [ADR-${adr.number}](adr-${adr.number}.md) - ${adr.title} - **${adr.status}** (${deciders})`;
        }),
        '',
        '<!-- adrlogstop -->',
        '',
        `_Generated on ${new Date().toISOString()}_`
      ].join('\n');

      return createSuccessResult({
        format: 'markdown',
        log: markdownLog,
        count: adrs.length
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to generate ADR log: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Setup ADR tools
 */
export async function setupADRTools(): Promise<ToolRegistration> {
  return {
    module: 'adr-management',
    tools: [
      createADRTool,
      createADRInteractiveTool,
      updateADRTool,
      linkADRsTool,
      getADRTool,
      listADRsTool,
      searchADRsTool,
      deleteADRTool,
      getADRMetricsTool,
      validateADRReferencesTool,
      generateADRLogTool
    ]
  };
}