import { Application, Request, Response } from 'express';
import { ensureDatabaseReady } from '../../storage/sqlite-manager.js';
import { randomUUID } from 'crypto';
import { setupAgileManagementTools } from '../../modules/agile-management/tools.js';
import { RequestContext } from '../../core/types.js';
import { 
  emitSprintCreated, 
  emitSprintUpdated, 
  emitStoryCreated, 
  emitStoryUpdated, 
  emitStoryMoved,
  emitEpicCreated,
  emitEpicUpdated 
} from '../utils/database-events.js';

// Helper function to safely parse JSON with fallback
function parseJsonSafely(jsonString: string | null | undefined, fallback: any = null): any {
  if (!jsonString) return fallback;
  
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    console.warn('Failed to parse JSON:', jsonString, error);
    return fallback;
  }
}

// Helper to create request context for tool execution (used by other endpoints)
async function createRequestContext(): Promise<RequestContext> {
  const db = await ensureDatabaseReady();
  return {
    toolName: 'dashboard',
    requestId: `req_${Date.now()}_${randomUUID()}`,
    timestamp: Date.now(),
    projectId: 'default',
    db
  };
}

export function setupAgileAPI(app: Application, agileManager: any): void {
  // Agile management API endpoints setup

  // Get all sprints
  app.get('/api/agile/sprints', async (req: Request, res: Response) => {
    try {
      const { status, limit = 50 } = req.query;
      let sprints = [];
      
      try {
        const db = await ensureDatabaseReady();
        
        let sql = 'SELECT * FROM agile_sprints WHERE 1=1';
        const params: any[] = [];
        
        if (status) {
          sql += ' AND status = ?';
          params.push(status);
        }
        
        sql += ' ORDER BY created_at DESC LIMIT ?';
        params.push(Number(limit));
        
        const result = await db.query(sql, params);
        
        if (result.success) {
          sprints = (result.data || []).map((sprint: any) => ({
            id: sprint.id,
            name: sprint.name,
            status: sprint.status,
            goal: sprint.goal,
            startDate: sprint.start_date ? new Date(sprint.start_date).toISOString() : null,
            endDate: sprint.end_date ? new Date(sprint.end_date).toISOString() : null,
            duration: sprint.duration,
            team: sprint.team ? JSON.parse(sprint.team) : [],
            storyPointsPlanned: sprint.story_points_planned || 0,
            storyPointsCompleted: sprint.story_points_completed || 0,
            storiesTotal: sprint.stories_total || 0,
            storiesCompleted: sprint.stories_completed || 0,
            velocity: sprint.velocity || 0,
            createdAt: new Date(sprint.created_at).toISOString(),
            updatedAt: new Date(sprint.updated_at).toISOString()
          }));
        } else {
          throw new Error(result.error || 'Database query failed');
        }
      } catch (dbError) {
        console.error('📋 Database error fetching sprints:', dbError);
        return res.status(503).json({
          success: false,
          error: 'Database unavailable',
          message: 'Unable to fetch sprints at this time'
        });
      }
      
      res.json({
        success: true,
        data: { sprints },
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching sprints:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch sprints',
        message: (error as Error).message
      });
    }
  });

  // Get active sprint
  app.get('/api/agile/sprints/active', async (req: Request, res: Response) => {
    try {
      let activeSprint = null;
      
      try {
        const db = await ensureDatabaseReady();
        
        const result = await db.get(
          'SELECT * FROM agile_sprints WHERE status = ? ORDER BY created_at DESC LIMIT 1',
          ['active']
        );
        
        if (result.success && result.data) {
          const sprint = result.data;
          activeSprint = {
            id: sprint.id,
            name: sprint.name,
            status: sprint.status,
            goal: sprint.goal,
            startDate: sprint.start_date ? new Date(sprint.start_date).toISOString() : null,
            endDate: sprint.end_date ? new Date(sprint.end_date).toISOString() : null,
            duration: sprint.duration,
            team: sprint.team ? JSON.parse(sprint.team) : [],
            storyPointsPlanned: sprint.story_points_planned || 0,
            storyPointsCompleted: sprint.story_points_completed || 0,
            storiesTotal: sprint.stories_total || 0,
            storiesCompleted: sprint.stories_completed || 0,
            velocity: sprint.velocity || 0,
            createdAt: new Date(sprint.created_at).toISOString(),
            updatedAt: new Date(sprint.updated_at).toISOString()
          };
        }
      } catch (dbError) {
        console.error('📋 Database error fetching active sprint:', dbError);
        return res.status(503).json({
          success: false,
          error: 'Database unavailable',
          message: 'Unable to fetch active sprint at this time'
        });
      }
      
      if (!activeSprint) {
        return res.status(404).json({
          success: false,
          error: 'No active sprint found'
        });
      }
      
      res.json({
        success: true,
        data: activeSprint,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching active sprint:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch active sprint',
        message: (error as Error).message
      });
    }
  });

  // Get specific sprint details
  app.get('/api/agile/sprints/:id', async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      console.error('🔍 Individual sprint request - ID:', id);
      
      // Validate that ID is not empty or whitespace
      if (!id || !id.trim()) {
        return res.status(404).json({
          success: false,
          error: 'Sprint not found',
          sprintId: id
        });
      }
      
      const db = await ensureDatabaseReady();
      console.error('✅ Database ready');
      
      // First, let's check if the sprint exists with a simple query
      const existsQuery = 'SELECT COUNT(*) as count FROM agile_sprints WHERE id = ?';
      const existsResult = await db.get(existsQuery, [id]);
      console.error('📊 Sprint exists check:', existsResult);
      
      // Get sprint from database (using SELECT * like the working list endpoint)
      const sprintQuery = `SELECT * FROM agile_sprints WHERE id = ?`;
      
      console.error('🔎 Executing sprint query with ID:', id);
      const sprintResult = await db.get(sprintQuery, [id]);
      console.error('📋 Sprint query result:', sprintResult);
      
      if (!sprintResult.success || !sprintResult.data) {
        return res.status(404).json({
          success: false,
          error: 'Sprint not found',
          sprintId: id
        });
      }
      
      // Convert to mutable object and map field names
      const rawSprint = sprintResult.data;
      const sprint: any = {
        id: rawSprint.id,
        project_id: rawSprint.project_id,
        name: rawSprint.name,
        goal: rawSprint.goal,
        status: rawSprint.status,
        startDate: rawSprint.start_date ? new Date(rawSprint.start_date).toISOString() : null,
        endDate: rawSprint.end_date ? new Date(rawSprint.end_date).toISOString() : null,
        duration: rawSprint.duration,
        team: parseJsonSafely(rawSprint.team, []),
        storyPointsPlanned: rawSprint.story_points_planned || 0,
        storyPointsCompleted: rawSprint.story_points_completed || 0,
        storiesTotal: rawSprint.stories_total || 0,
        storiesCompleted: rawSprint.stories_completed || 0,
        velocity: rawSprint.velocity || 0,
        createdAt: new Date(rawSprint.created_at).toISOString(),
        updatedAt: new Date(rawSprint.updated_at).toISOString()
      };
      
      // Get stories for this sprint to calculate statistics
      const storiesQuery = `
        SELECT 
          id,
          title,
          status,
          story_points as storyPoints
        FROM agile_stories 
        WHERE sprint_id = ?
      `;
      
      const storiesResult = await db.all(storiesQuery, [id]);
      const stories = storiesResult.data || [];
      
      // Calculate statistics from stories
      const completedStories = stories.filter((s: any) => s.status === 'done');
      const totalPoints = stories.reduce((sum: number, s: any) => sum + (s.storyPoints || 0), 0);
      const completedPoints = completedStories.reduce((sum: number, s: any) => sum + (s.storyPoints || 0), 0);
      
      // Update sprint with calculated fields
      sprint.storyPointsPlanned = sprint.storyPointsPlanned || totalPoints;
      sprint.storyPointsCompleted = completedPoints;
      sprint.storiesTotal = stories.length;
      sprint.storiesCompleted = completedStories.length;
      sprint.velocity = completedPoints;
      sprint.weeklyRate = sprint.duration ? (completedPoints / (sprint.duration / 7)).toFixed(1) : 0;
      
      // Update the sprint in database with calculated values
      const updateQuery = `
        UPDATE agile_sprints 
        SET 
          story_points_planned = ?,
          story_points_completed = ?,
          stories_total = ?,
          stories_completed = ?,
          velocity = ?,
          updated_at = ?
        WHERE id = ?
      `;
      
      await db.run(updateQuery, [
        sprint.storyPointsPlanned,
        sprint.storyPointsCompleted,
        sprint.storiesTotal,
        sprint.storiesCompleted,
        sprint.velocity,
        Math.floor(Date.now() / 1000),
        id
      ]);
      
      res.json({
        success: true,
        data: sprint,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error(`📋 Error fetching sprint ${req.params.id}:`, error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch sprint details',
        message: (error as Error).message
      });
    }
  });

  // Get stories with filtering
  app.get('/api/agile/stories', async (req: Request, res: Response) => {
    try {
      const { 
        sprintId,
        epicId, 
        status, 
        assignee, 
        priority,
        limit = 50,
        offset = 0 
      } = req.query;
      
      const filters = {
        sprintId,
        status,
        assignee,
        priority,
        limit: Number(limit),
        offset: Number(offset)
      };
      
      let stories = [];
      
      // Use appropriate method based on filters
      if (sprintId && agileManager.getStoriesForSprint) {
        // Get stories for specific sprint
        stories = await agileManager.getStoriesForSprint(sprintId as string);
      } else if (agileManager.getAllStories) {
        // Get all stories
        stories = await agileManager.getAllStories();
      } else if (agileManager.getBacklog) {
        // Fallback to getBacklog only if no sprintId is specified
        if (!sprintId) {
          stories = await agileManager.getBacklog();
        } else {
          // If sprintId is specified but we only have getBacklog, return empty
          stories = [];
        }
      } else {
        // Try to fetch from database
        try {
          const db = await ensureDatabaseReady();
          
          let sql = 'SELECT * FROM agile_stories WHERE 1=1';
          const params: any[] = [];
          
          if (status) {
            sql += ' AND status = ?';
            params.push(status);
          }
          if (assignee) {
            sql += ' AND assignee LIKE ?';
            params.push(`%${assignee}%`);
          }
          if (priority) {
            sql += ' AND priority = ?';
            params.push(priority);
          }
          if (sprintId) {
            sql += ' AND sprint_id = ?';
            params.push(sprintId);
          }
          if (epicId) {
            sql += ' AND epic_id = ?';
            params.push(epicId);
          }
          
          sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
          params.push(Number(limit), Number(offset));
          
          const result = await db.query(sql, params);
          
          if (result.success) {
            stories = (result.data || []).map((story: any) => ({
              id: story.id,
              title: story.title,
              description: story.description,
              status: story.status,
              storyPoints: story.story_points,
              assignee: story.assignee,
              priority: story.priority,
              sprintId: story.sprint_id,
              epicId: story.epic_id,
              tags: story.tags ? JSON.parse(story.tags) : [],
              createdAt: new Date(story.created_at).toISOString(),
              updatedAt: new Date(story.updated_at).toISOString()
            }));
          } else {
            throw new Error(result.error || 'Database query failed');
          }
        } catch (dbError) {
          console.error('📋 Database error fetching stories:', dbError);
          return res.status(503).json({
            success: false,
            error: 'Database unavailable',
            message: 'Unable to fetch stories at this time'
          });
        }
      }
      
      // Apply filters for agileManager-returned data (database queries already filter)
      if (stories && !sprintId && (status || assignee || priority || epicId)) {
        if (status) {
          stories = stories.filter((story: any) => story.status === status);
        }
        if (assignee) {
          stories = stories.filter((story: any) => story.assignee === assignee);
        }
        if (priority) {
          stories = stories.filter((story: any) => story.priority === priority);
        }
        if (epicId) {
          stories = stories.filter((story: any) => story.epic === epicId || story.epicId === epicId);
        }
      }
      
      // Apply pagination for agileManager-returned data (database queries already paginate)
      if (stories && agileManager.getAllStories) {
        const startIndex = Number(offset);
        const endIndex = startIndex + Number(limit);
        stories = stories.slice(startIndex, endIndex);
      }
      
      res.json({
        success: true,
        data: { stories },
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching stories:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch stories',
        message: (error as Error).message
      });
    }
  });

  // Move story between columns
  app.post('/api/agile/story/move', async (req: Request, res: Response) => {
    try {
      const { storyId, fromStatus, toStatus, index } = req.body;
      
      if (!storyId || !toStatus) {
        return res.status(400).json({
          success: false,
          error: 'Missing required fields: storyId and toStatus are required'
        });
      }

      let result = null;
      
      if (agileManager.moveStory) {
        result = await agileManager.moveStory(storyId, toStatus, index);
      } else if (agileManager.updateStory) {
        result = await agileManager.updateStory(storyId, { status: toStatus });
      } else {
        // Try to update in database
        try {
          const db = await ensureDatabaseReady();
          
          const updateResult = await db.run(
            'UPDATE agile_stories SET status = ?, updated_at = ? WHERE id = ?',
            [toStatus, Date.now(), storyId]
          );
          
          if (updateResult.success && updateResult.data.changes > 0) {
            result = {
              storyId,
              fromStatus,
              toStatus,
              index,
              updatedAt: new Date().toISOString()
            };
          } else {
            throw new Error('Story not found or update failed');
          }
        } catch (dbError) {
          console.error('📋 Database error updating story:', dbError);
          return res.status(503).json({
            success: false,
            error: 'Database unavailable',
            message: 'Unable to update story at this time'
          });
        }
      }
      
      res.json({
        success: true,
        message: 'Story moved successfully',
        data: result,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error moving story:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to move story',
        message: (error as Error).message
      });
    }
  });

  // Get individual story details
  app.get('/api/agile/stories/:id', async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      let story = null;
      
      try {
        const db = await ensureDatabaseReady();
        
        const result = await db.get(
          'SELECT * FROM agile_stories WHERE id = ?',
          [id]
        );
        
        if (result.success && result.data) {
          const rawStory = result.data;
          story = {
            id: rawStory.id,
            title: rawStory.title,
            description: rawStory.description,
            status: rawStory.status,
            storyPoints: rawStory.story_points || 0,
            priority: rawStory.priority,
            assignee: rawStory.assignee,
            sprintId: rawStory.sprint_id,
            epicId: rawStory.epic_id,
            tags: parseJsonSafely(rawStory.tags, []),
            acceptanceCriteria: parseJsonSafely(rawStory.acceptance_criteria, []),
            designDocumentUrl: rawStory.design_document_url,
            implementationDocumentUrl: rawStory.implementation_document_url,
            documentationStatus: rawStory.documentation_status,
            groomedWithUserFeedback: rawStory.groomed_with_user_feedback,
            createdAt: new Date(rawStory.created_at).toISOString(),
            updatedAt: new Date(rawStory.updated_at).toISOString()
          };
        }
      } catch (dbError) {
        console.error('📋 Database error fetching story details:', dbError);
        return res.status(503).json({
          success: false,
          error: 'Database unavailable',
          message: 'Unable to fetch story details at this time'
        });
      }
      
      if (!story) {
        return res.status(404).json({
          success: false,
          error: 'Story not found'
        });
      }
      
      res.json({
        success: true,
        data: story,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching story:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch story',
        message: (error as Error).message
      });
    }
  });

  // Update story details
  app.put('/api/agile/stories/:id', async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      const updates = req.body;
      
      let result = null;
      
      if (agileManager.updateStory) {
        result = await agileManager.updateStory(id, updates);
      } else {
        // Try to update in database
        try {
          const db = await ensureDatabaseReady();
          
          // Build dynamic update query
          const updateFields = [];
          const updateValues = [];
          
          if (updates.title !== undefined) {
            updateFields.push('title = ?');
            updateValues.push(updates.title);
          }
          if (updates.description !== undefined) {
            updateFields.push('description = ?');
            updateValues.push(updates.description);
          }
          if (updates.status !== undefined) {
            updateFields.push('status = ?');
            updateValues.push(updates.status);
          }
          if (updates.storyPoints !== undefined) {
            updateFields.push('story_points = ?');
            updateValues.push(updates.storyPoints);
          }
          if (updates.priority !== undefined) {
            updateFields.push('priority = ?');
            updateValues.push(updates.priority);
          }
          if (updates.assignee !== undefined) {
            updateFields.push('assignee = ?');
            updateValues.push(updates.assignee);
          }
          if (updates.tags !== undefined) {
            updateFields.push('tags = ?');
            updateValues.push(JSON.stringify(updates.tags));
          }
          if (updates.acceptanceCriteria !== undefined) {
            updateFields.push('acceptance_criteria = ?');
            updateValues.push(JSON.stringify(updates.acceptanceCriteria));
          }
          
          updateFields.push('updated_at = ?');
          updateValues.push(Date.now());
          updateValues.push(id);
          
          const updateResult = await db.run(
            `UPDATE agile_stories SET ${updateFields.join(', ')} WHERE id = ?`,
            updateValues
          );
          
          if (updateResult.success && updateResult.data.changes > 0) {
            result = {
              storyId: id,
              updates,
              updatedAt: new Date().toISOString()
            };
          } else {
            throw new Error('Story not found or update failed');
          }
        } catch (dbError) {
          console.error('📋 Database error updating story:', dbError);
          return res.status(503).json({
            success: false,
            error: 'Database unavailable',
            message: 'Unable to update story at this time'
          });
        }
      }
      
      // Emit story updated event
      emitStoryUpdated(id, updates);
      
      res.json({
        success: true,
        message: 'Story updated successfully',
        data: result,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error(`📋 Error updating story ${req.params.id}:`, error);
      res.status(500).json({
        success: false,
        error: 'Failed to update story',
        message: (error as Error).message
      });
    }
  });

  // Get velocity data for charts
  app.get('/api/agile/velocity', async (req: Request, res: Response) => {
    try {
      const { teamName, sprints = '5' } = req.query;
      const db = await ensureDatabaseReady();
      
      // Get completed sprints ordered by end date
      const sprintsResult = await db.all(
        `SELECT * FROM agile_sprints 
         WHERE status IN ('completed', 'done') 
         ORDER BY end_date DESC 
         LIMIT ?`,
        [Number(sprints)]
      );
      
      const completedSprints = (sprintsResult.data || []).reverse(); // Show oldest to newest
      
      // If no completed sprints, include active sprint
      if (completedSprints.length === 0) {
        const activeResult = await db.all(
          `SELECT * FROM agile_sprints 
           WHERE status = 'active' 
           ORDER BY start_date DESC 
           LIMIT ?`,
          [Number(sprints)]
        );
        completedSprints.push(...(activeResult.data || []));
      }
      
      // Calculate velocity for each sprint
      const velocityData = {
        labels: [],
        plannedPoints: [],
        completedPoints: [],
        averageVelocity: 0,
        currentVelocity: 0,
        trend: 'stable',
        sprints: []
      };
      
      let totalVelocity = 0;
      let velocityCount = 0;
      
      for (const sprint of completedSprints) {
        // Get stories for this sprint to calculate actual velocity
        const storiesResult = await db.all(
          'SELECT story_points, status FROM agile_stories WHERE sprint_id = ?',
          [sprint.id]
        );
        
        const stories = storiesResult.data || [];
        const totalPoints = stories.reduce((sum, s) => sum + (s.story_points || 0), 0);
        const completedPoints = stories
          .filter(s => s.status === 'done')
          .reduce((sum, s) => sum + (s.story_points || 0), 0);
        
        velocityData.labels.push(sprint.name);
        velocityData.plannedPoints.push(totalPoints);
        velocityData.completedPoints.push(completedPoints);
        
        if (completedPoints > 0) {
          totalVelocity += completedPoints;
          velocityCount++;
        }
        
        velocityData.sprints.push({
          id: sprint.id,
          name: sprint.name,
          plannedPoints: totalPoints,
          completedPoints: completedPoints,
          startDate: sprint.start_date,
          endDate: sprint.end_date
        });
      }
      
      // Calculate average and current velocity
      velocityData.averageVelocity = velocityCount > 0 ? Math.round(totalVelocity / velocityCount) : 0;
      velocityData.currentVelocity = velocityData.completedPoints[velocityData.completedPoints.length - 1] || 0;
      
      // Determine trend
      if (velocityData.completedPoints.length >= 2) {
        const recent = velocityData.completedPoints.slice(-3);
        const older = velocityData.completedPoints.slice(-6, -3);
        const recentAvg = recent.reduce((a, b) => a + b, 0) / recent.length;
        const olderAvg = older.length > 0 ? older.reduce((a, b) => a + b, 0) / older.length : recentAvg;
        
        if (recentAvg > olderAvg * 1.1) velocityData.trend = 'improving';
        else if (recentAvg < olderAvg * 0.9) velocityData.trend = 'declining';
      }
      
      res.json({
        success: true,
        data: velocityData,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching velocity data:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch velocity data',
        message: (error as Error).message
      });
    }
  });

  // Get burndown chart data for a sprint
  app.get('/api/agile/burndown/:sprintId', async (req: Request, res: Response) => {
    try {
      const { sprintId } = req.params;
      const db = await ensureDatabaseReady();
      
      // Get sprint details
      const sprintResult = await db.get(
        'SELECT * FROM agile_sprints WHERE id = ?',
        [sprintId]
      );
      
      if (!sprintResult.success || !sprintResult.data) {
        return res.status(404).json({
          success: false,
          error: 'Sprint not found'
        });
      }
      
      const sprint = sprintResult.data;
      
      // Get all stories for this sprint
      const storiesResult = await db.all(
        'SELECT id, story_points, status, updated_at FROM agile_stories WHERE sprint_id = ?',
        [sprintId]
      );
      
      const stories = storiesResult.data || [];
      const totalPoints = stories.reduce((sum, story) => sum + (story.story_points || 0), 0);
      
      // Generate burndown data
      const startDate = new Date(sprint.start_date * 1000);
      const endDate = new Date(sprint.end_date * 1000);
      const duration = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
      
      // Create ideal burndown line
      const idealBurndown = [];
      const actualBurndown = [];
      const labels = [];
      
      for (let day = 0; day <= duration; day++) {
        const date = new Date(startDate);
        date.setDate(date.getDate() + day);
        
        // Ideal burndown: linear from total to 0
        const idealRemaining = totalPoints - (totalPoints * (day / duration));
        idealBurndown.push(Math.round(idealRemaining * 10) / 10);
        
        // Actual burndown: calculate based on story completions up to this date
        const dateTimestamp = date.getTime() / 1000;
        const completedPoints = stories
          .filter(story => story.status === 'done' && story.updated_at <= dateTimestamp)
          .reduce((sum, story) => sum + (story.story_points || 0), 0);
        const actualRemaining = totalPoints - completedPoints;
        actualBurndown.push(actualRemaining);
        
        // Date labels
        labels.push(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
      }
      
      const burndownData = {
        sprintId,
        sprintName: sprint.name,
        totalStoryPoints: totalPoints,
        completedPoints: totalPoints - actualBurndown[actualBurndown.length - 1],
        labels,
        idealBurndown,
        actualBurndown,
        startDate: sprint.start_date,
        endDate: sprint.end_date
      };
      
      res.json({
        success: true,
        data: burndownData,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error(`📋 Error fetching burndown data for sprint ${req.params.sprintId}:`, error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch burndown data',
        message: (error as Error).message
      });
    }
  });

  // Get board configuration (columns, workflow states)
  app.get('/api/agile/board/config', async (req: Request, res: Response) => {
    try {
      let boardConfig = null;
      
      if (agileManager.getBoardConfig) {
        boardConfig = await agileManager.getBoardConfig();
      }
      
      if (!boardConfig) {
        return res.status(404).json({
          success: false,
          error: 'Board configuration not available'
        });
      }
      
      res.json({
        success: true,
        data: boardConfig,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching board configuration:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch board configuration',
        message: (error as Error).message
      });
    }
  });

  // Health check for agile service
  app.get('/api/agile/health', async (req: Request, res: Response) => {
    try {
      const features = {
        sprints: !!agileManager.getSprints || !!agileManager.getCurrentSprints,
        stories: !!agileManager.getStories || !!agileManager.getActiveStories,
        velocity: !!agileManager.getVelocityData,
        burndown: !!agileManager.getBurndownData,
        storyUpdates: !!agileManager.updateStory,
        storyMovement: !!agileManager.moveStory
      };
      
      res.json({
        success: true,
        status: 'healthy',
        data: {
          agileManagerAvailable: !!agileManager,
          features
        },
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Agile service health check failed:', error);
      res.status(503).json({
        success: false,
        status: 'unhealthy',
        error: 'Agile service is not functioning properly',
        message: (error as Error).message,
        timestamp: new Date().toISOString()
      });
    }
  });

  // Get all boards
  app.get('/api/agile/boards', async (req: Request, res: Response) => {
    try {
      let boards = [];
      
      if (agileManager.getBoards) {
        boards = await agileManager.getBoards();
      }
      
      res.json({
        success: true,
        data: boards,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching boards:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch boards',
        message: (error as Error).message
      });
    }
  });

  // Create a new board
  app.post('/api/agile/boards', async (req: Request, res: Response) => {
    try {
      const { name, columns } = req.body;
      
      if (!name || !columns || !Array.isArray(columns)) {
        return res.status(400).json({
          success: false,
          error: 'Board name and columns are required'
        });
      }
      
      let board = null;
      
      if (agileManager.createBoard) {
        board = await agileManager.createBoard({ name, columns });
      } else {
        return res.status(501).json({
          success: false,
          error: 'Board creation not implemented'
        });
      }
      
      res.status(201).json({
        success: true,
        data: board,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error creating board:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to create board',
        message: (error as Error).message
      });
    }
  });

  // Get backlog items
  app.get('/api/agile/backlog', async (req: Request, res: Response) => {
    try {
      const options = {
        includeEstimates: req.query.includeEstimates === 'true',
        maxItems: Number(req.query.maxItems) || 20
      };
      
      let backlog = [];
      
      if (agileManager.getBacklogItems) {
        backlog = await agileManager.getBacklogItems(options);
      }
      
      res.json({
        success: true,
        data: backlog,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching backlog:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch backlog',
        message: (error as Error).message
      });
    }
  });

  // Estimate a story
  app.post('/api/agile/estimate', async (req: Request, res: Response) => {
    try {
      const { storyId, estimates, finalEstimate } = req.body;
      
      let result = null;
      
      if (agileManager.estimateStory) {
        result = await agileManager.estimateStory(storyId, req.body);
      } else {
        return res.status(501).json({
          success: false,
          error: 'Story estimation not implemented'
        });
      }
      
      res.json({
        success: true,
        data: result,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error estimating story:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to estimate story',
        message: (error as Error).message
      });
    }
  });

  // Get team capacity for sprint
  app.get('/api/agile/capacity/:sprintId', async (req: Request, res: Response) => {
    try {
      const { sprintId } = req.params;
      
      let capacity = null;
      
      if (agileManager.getTeamCapacity) {
        capacity = await agileManager.getTeamCapacity(sprintId);
      }
      
      if (!capacity) {
        return res.status(404).json({
          success: false,
          error: 'Team capacity data not available'
        });
      }
      
      res.json({
        success: true,
        data: capacity,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching team capacity:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch team capacity',
        message: (error as Error).message
      });
    }
  });

  // Generate sprint report
  app.get('/api/agile/report/:sprintId', async (req: Request, res: Response) => {
    try {
      const { sprintId } = req.params;
      const options = {
        includeMetrics: req.query.includeMetrics === 'true',
        includeStories: true,
        includeRetrospective: false,
        format: req.query.format as string || 'detailed'
      };
      
      let report = null;
      
      if (agileManager.generateSprintReport) {
        report = await agileManager.generateSprintReport(sprintId, options);
      }
      
      if (!report) {
        return res.status(404).json({
          success: false,
          error: 'Sprint report not available'
        });
      }
      
      res.json({
        success: true,
        data: report,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error generating sprint report:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to generate sprint report',
        message: (error as Error).message
      });
    }
  });

  // Epic endpoints
  
  // Get all epics
  app.get('/api/agile/epics', async (req: Request, res: Response) => {
    try {
      const { status, priority, limit = 100, offset = 0 } = req.query;
      
      let epics = [];
      
      // Get epics from database instead of agileManager
      try {
        const db = await ensureDatabaseReady();
        console.error('📋 Fetching epics from database - DB ready');
        
        let sql = 'SELECT * FROM agile_epics WHERE 1=1';
        const params: any[] = [];
        
        if (status) {
          sql += ' AND status = ?';
          params.push(status);
        }
        if (priority) {
          sql += ' AND priority = ?';
          params.push(priority);
        }
        
        sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
        params.push(Number(limit), Number(offset));
        
        console.error(`📋 Executing epics query: ${sql} with params:`, params);
        const result = await db.query(sql, params);
        console.error('📋 Epics query result:', { success: result.success, count: result.data?.length || 0 });
        
        if (result.success) {
          epics = (result.data || []).map((epic: any) => ({
            id: epic.id,
            title: epic.title,
            description: epic.description,
            status: epic.status,
            storyPoints: epic.story_points || 0,
            priority: epic.priority,
            targetQuarter: epic.target_quarter,
            businessValue: epic.business_value,
            successCriteria: parseJsonSafely(epic.success_criteria, []),
            dependencies: parseJsonSafely(epic.dependencies, []),
            risks: parseJsonSafely(epic.risks, []),
            createdAt: new Date(epic.created_at * 1000).toISOString(),
            updatedAt: new Date(epic.updated_at * 1000).toISOString()
          }));
        } else {
          throw new Error(result.error || 'Database query failed');
        }
      } catch (dbError) {
        console.error('📋 Database error fetching epics:', dbError);
        return res.status(503).json({
          success: false,
          error: 'Database unavailable',
          message: 'Unable to fetch epics at this time'
        });
      }
      
      res.json({
        success: true,
        data: { epics },
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching epics:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch epics',
        message: (error as Error).message
      });
    }
  });

  // Get specific epic details
  app.get('/api/agile/epic/:id', async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      
      let epic = null;
      
      // Get epic from database instead of agileManager
      try {
        const db = await ensureDatabaseReady();
        const result = await db.get('SELECT * FROM agile_epics WHERE id = ?', [id]);
        
        if (result.success && result.data) {
          const rawEpic = result.data;
          epic = {
            id: rawEpic.id,
            title: rawEpic.title,
            description: rawEpic.description,
            status: rawEpic.status,
            storyPoints: rawEpic.story_points || 0,
            priority: rawEpic.priority,
            targetQuarter: rawEpic.target_quarter,
            businessValue: rawEpic.business_value,
            successCriteria: parseJsonSafely(rawEpic.success_criteria, []),
            dependencies: parseJsonSafely(rawEpic.dependencies, []),
            risks: parseJsonSafely(rawEpic.risks, []),
            createdAt: new Date(rawEpic.created_at * 1000).toISOString(),
            updatedAt: new Date(rawEpic.updated_at * 1000).toISOString()
          };
        }
      } catch (dbError) {
        console.error('📋 Database error fetching epic details:', dbError);
        return res.status(503).json({
          success: false,
          error: 'Database unavailable',
          message: 'Unable to fetch epic details at this time'
        });
      }
      
      if (!epic) {
        return res.status(404).json({
          success: false,
          error: 'Epic not found',
          epicId: id
        });
      }
      
      res.json({
        success: true,
        data: epic,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error(`📋 Error fetching epic ${req.params.id}:`, error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch epic details',
        message: (error as Error).message
      });
    }
  });

  // Get stories for a specific epic
  app.get('/api/agile/stories', async (req: Request, res: Response) => {
    try {
      const { 
        sprintId, 
        epicId,
        status, 
        assignee, 
        priority,
        limit = 50,
        offset = 0 
      } = req.query;
      
      const filters = {
        sprintId,
        epicId,
        status,
        assignee,
        priority,
        limit: Number(limit),
        offset: Number(offset)
      };
      
      let stories = [];
      
      if (agileManager.getBacklog) {
        // Use the available getBacklog method to get all stories
        const allStories = await agileManager.getBacklog();
        stories = allStories;
        
        // Apply filters
        if (sprintId) {
          stories = stories.filter((story: any) => story.sprintId === sprintId);
        }
        if (epicId) {
          stories = stories.filter((story: any) => story.epic === epicId);
        }
        if (status) {
          stories = stories.filter((story: any) => story.status === status);
        }
        if (assignee) {
          stories = stories.filter((story: any) => story.assignee === assignee);
        }
        if (priority) {
          stories = stories.filter((story: any) => story.priority === priority);
        }
        
        // Apply pagination
        const startIndex = Number(offset);
        const endIndex = startIndex + Number(limit);
        stories = stories.slice(startIndex, endIndex);
      }
      
      res.json({
        success: true,
        data: { stories },
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching stories:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch stories',
        message: (error as Error).message
      });
    }
  });

  // Add alias endpoint for dashboard compatibility
  app.get('/api/agile/sprint/:id', async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      const db = await ensureDatabaseReady();
      
      // Get sprint from database
      const sprintQuery = `
        SELECT 
          id,
          project_id,
          name,
          goal,
          status,
          start_date as startDate,
          end_date as endDate,
          duration,
          team,
          story_points_planned as storyPointsPlanned,
          story_points_completed as storyPointsCompleted,
          stories_total as storiesTotal,
          stories_completed as storiesCompleted,
          velocity,
          created_at as createdAt,
          updated_at as updatedAt
        FROM agile_sprints 
        WHERE id = ?
      `;
      
      const sprintResult = await db.get(sprintQuery, [id]);
      
      if (!sprintResult.success || !sprintResult.data) {
        return res.status(404).json({
          success: false,
          error: 'Sprint not found',
          sprintId: id
        });
      }
      
      // Convert to mutable object
      const sprint: any = { ...sprintResult.data };
      
      // Parse JSON fields
      sprint.team = parseJsonSafely(sprint.team, []);
      
      // Get stories for this sprint to calculate statistics
      const storiesQuery = `
        SELECT 
          id,
          title,
          description,
          status,
          story_points as storyPoints,
          priority,
          assignee,
          acceptance_criteria as acceptanceCriteria,
          created_at as createdAt,
          updated_at as updatedAt
        FROM agile_stories 
        WHERE sprint_id = ?
      `;
      
      const storiesResult = await db.all(storiesQuery, [id]);
      const stories = storiesResult.data || [];
      
      // Parse JSON fields in stories
      stories.forEach((story: any) => {
        story.acceptanceCriteria = parseJsonSafely(story.acceptanceCriteria, []);
      });
      
      // Calculate statistics from stories
      const completedStories = stories.filter((s: any) => s.status === 'done');
      const totalPoints = stories.reduce((sum: number, s: any) => sum + (s.storyPoints || 0), 0);
      const completedPoints = completedStories.reduce((sum: number, s: any) => sum + (s.storyPoints || 0), 0);
      
      // Update sprint with calculated fields
      sprint.storyPointsPlanned = sprint.storyPointsPlanned || totalPoints;
      sprint.storyPointsCompleted = completedPoints;
      sprint.storiesTotal = stories.length;
      sprint.storiesCompleted = completedStories.length;
      sprint.velocity = completedPoints;
      sprint.weeklyRate = sprint.duration ? (completedPoints / (sprint.duration / 7)).toFixed(1) : 0;
      
      const sprintData = {
        ...sprint,
        stories: stories
      };
      
      res.json({
        success: true,
        data: sprintData,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      console.error('📋 Error fetching sprint:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to fetch sprint',
        message: (error as Error).message
      });
    }
  });

  // ==========================================
  // Data Generation Endpoints (POST)
  // ==========================================

  // Create a new sprint
  app.post('/api/agile/sprints', async (req: Request, res: Response) => {
    try {
      const { name, goal, startDate, endDate, duration } = req.body;
      
      if (!name || !goal) {
        return res.status(400).json({
          success: false,
          error: 'Missing required fields: name and goal are required'
        });
      }

      const db = await ensureDatabaseReady();
      const id = randomUUID();
      const now = Math.floor(Date.now() / 1000);
      
      // Calculate dates
      const start = startDate ? new Date(startDate) : new Date();
      const end = endDate ? new Date(endDate) : new Date(Date.now() + (duration || 14) * 24 * 60 * 60 * 1000);
      const durationDays = duration || 14;
      
      const result = await db.run(
        `INSERT INTO agile_sprints (
          id, project_id, name, goal, status, start_date, end_date, duration,
          team, story_points_planned, story_points_completed, stories_total,
          stories_completed, velocity, created_at, updated_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          id,
          'default', // project_id
          name,
          goal,
          'planning', // status
          Math.floor(start.getTime() / 1000), // start_date as unix timestamp
          Math.floor(end.getTime() / 1000), // end_date as unix timestamp
          durationDays,
          '[]', // team as JSON array
          0, // story_points_planned
          0, // story_points_completed
          0, // stories_total
          0, // stories_completed
          0, // velocity
          now, // created_at
          now // updated_at
        ]
      );

      if (result.success) {
        const sprint = {
          id,
          name,
          goal,
          status: 'planning',
          startDate: start.toISOString(),
          endDate: end.toISOString(),
          duration: durationDays,
          team: [],
          storyPointsPlanned: 0,
          storyPointsCompleted: 0,
          storiesTotal: 0,
          storiesCompleted: 0,
          velocity: 0,
          createdAt: new Date(now * 1000).toISOString(),
          updatedAt: new Date(now * 1000).toISOString()
        };
        
        // Emit sprint created event
        emitSprintCreated(sprint);
        
        res.status(201).json({
          success: true,
          data: sprint,
          timestamp: new Date().toISOString()
        });
      } else {
        res.status(400).json({
          success: false,
          error: result.error || 'Failed to create sprint'
        });
      }
    } catch (error) {
      console.error('📋 Error creating sprint:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to create sprint',
        message: (error as Error).message
      });
    }
  });

  // Create a new story
  app.post('/api/agile/stories', async (req: Request, res: Response) => {
    try {
      const { title, description, acceptanceCriteria, storyPoints, priority, tags, sprintId, epicId, assignee } = req.body;
      
      if (!title) {
        return res.status(400).json({
          success: false,
          error: 'Missing required field: title'
        });
      }

      const db = await ensureDatabaseReady();
      const id = randomUUID();
      const now = Math.floor(Date.now() / 1000);
      
      const result = await db.run(
        `INSERT INTO agile_stories (
          id, project_id, sprint_id, epic_id, title, description, status,
          story_points, priority, assignee, tags, acceptance_criteria,
          design_document_url, implementation_document_url, documentation_status,
          groomed_with_user_feedback, created_at, updated_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          id,
          'default', // project_id
          sprintId || null, // sprint_id
          epicId || null, // epic_id
          title,
          description || '',
          'backlog', // status - new stories start in backlog
          storyPoints || 0,
          priority || 'medium',
          assignee || null,
          JSON.stringify(tags || []),
          JSON.stringify(acceptanceCriteria || []),
          null, // design_document_url
          null, // implementation_document_url
          'pending', // documentation_status
          false, // groomed_with_user_feedback
          now, // created_at
          now // updated_at
        ]
      );

      if (result.success) {
        const story = {
          id,
          title,
          description: description || '',
          status: 'backlog',
          storyPoints: storyPoints || 0,
          priority: priority || 'medium',
          assignee: assignee || null,
          sprintId: sprintId || null,
          epicId: epicId || null,
          tags: tags || [],
          acceptanceCriteria: acceptanceCriteria || [],
          designDocumentUrl: null,
          implementationDocumentUrl: null,
          documentationStatus: 'pending',
          groomedWithUserFeedback: false,
          createdAt: new Date(now * 1000).toISOString(),
          updatedAt: new Date(now * 1000).toISOString()
        };
        
        // Emit story created event
        emitStoryCreated(story);
        
        res.status(201).json({
          success: true,
          data: story,
          timestamp: new Date().toISOString()
        });
      } else {
        res.status(400).json({
          success: false,
          error: result.error || 'Failed to create story'
        });
      }
    } catch (error) {
      console.error('📋 Error creating story:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to create story',
        message: (error as Error).message
      });
    }
  });

  // Create a new epic
  app.post('/api/agile/epics', async (req: Request, res: Response) => {
    try {
      const { title, description, businessValue, successCriteria, priority, targetQuarter, dependencies, risks } = req.body;
      
      if (!title || !description) {
        return res.status(400).json({
          success: false,
          error: 'Missing required fields: title and description are required'
        });
      }

      const db = await ensureDatabaseReady();
      const id = randomUUID();
      const now = Math.floor(Date.now() / 1000);
      
      const result = await db.run(
        `INSERT INTO agile_epics (
          id, project_id, title, description, status, story_points,
          priority, target_quarter, business_value, success_criteria,
          dependencies, risks, created_at, updated_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          id,
          'default', // project_id
          title,
          description,
          'planning', // status - new epics start in planning
          0, // story_points - will be calculated from stories
          priority || 'medium',
          targetQuarter || null,
          businessValue || '',
          JSON.stringify(successCriteria || []),
          JSON.stringify(dependencies || []),
          JSON.stringify(risks || []),
          now, // created_at
          now // updated_at
        ]
      );

      if (result.success) {
        const epic = {
          id,
          title,
          description,
          status: 'planning',
          storyPoints: 0,
          priority: priority || 'medium',
          targetQuarter: targetQuarter || null,
          businessValue: businessValue || '',
          successCriteria: successCriteria || [],
          dependencies: dependencies || [],
          risks: risks || [],
          createdAt: new Date(now * 1000).toISOString(),
          updatedAt: new Date(now * 1000).toISOString()
        };
        
        // Emit epic created event
        emitEpicCreated(epic);
        
        res.status(201).json({
          success: true,
          data: epic,
          timestamp: new Date().toISOString()
        });
      } else {
        res.status(400).json({
          success: false,
          error: result.error || 'Failed to create epic'
        });
      }
    } catch (error) {
      console.error('📋 Error creating epic:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to create epic',
        message: (error as Error).message
      });
    }
  });

  // Add story to sprint
  app.post('/api/agile/sprints/:sprintId/stories/:storyId', async (req: Request, res: Response) => {
    try {
      const { sprintId, storyId } = req.params;

      // Get the agile tools
      const agileTools = await setupAgileManagementTools();
      const addToSprintTool = agileTools.tools.find(t => t.name === 'add_story_to_sprint');
      
      if (!addToSprintTool) {
        return res.status(500).json({
          success: false,
          error: 'Add to sprint tool not available'
        });
      }

      // Create request context
      const context = await createRequestContext();
      
      // Execute the tool
      const result = await addToSprintTool.execute({
        storyId,
        sprintId
      }, context);

      if (result.success) {
        res.json({
          success: true,
          data: result.data,
          timestamp: new Date().toISOString()
        });
      } else {
        res.status(400).json({
          success: false,
          error: result.error?.message || 'Failed to add story to sprint'
        });
      }
    } catch (error) {
      console.error('📋 Error adding story to sprint:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to add story to sprint',
        message: (error as Error).message
      });
    }
  });

  // Update story status
  app.patch('/api/agile/stories/:storyId/status', async (req: Request, res: Response) => {
    try {
      const { storyId } = req.params;
      const { status } = req.body;

      if (!status) {
        return res.status(400).json({
          success: false,
          error: 'Missing required field: status'
        });
      }

      // Get the agile tools
      const agileTools = await setupAgileManagementTools();
      const updateStatusTool = agileTools.tools.find(t => t.name === 'update_story_status');
      
      if (!updateStatusTool) {
        return res.status(500).json({
          success: false,
          error: 'Update status tool not available'
        });
      }

      // Create request context
      const context = await createRequestContext();
      
      // Execute the tool
      const result = await updateStatusTool.execute({
        storyId,
        status
      }, context);

      if (result.success) {
        // Emit story moved event when status changes
        if (result.data?.oldStatus && result.data?.newStatus) {
          emitStoryMoved(storyId, result.data.oldStatus, result.data.newStatus);
        } else {
          // If we don't have old/new status in result, just emit an update
          emitStoryUpdated(storyId, { status });
        }
        
        res.json({
          success: true,
          data: result.data,
          timestamp: new Date().toISOString()
        });
      } else {
        res.status(400).json({
          success: false,
          error: result.error?.message || 'Failed to update story status'
        });
      }
    } catch (error) {
      console.error('📋 Error updating story status:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to update story status',
        message: (error as Error).message
      });
    }
  });
}