from fastapi import APIRouter, HTTPException from app.core.database import execute_query from typing import List, Optional, Dict, Any from pydantic import BaseModel from datetime import date, datetime import logging logger = logging.getLogger(__name__) router = APIRouter() # Pydantic Models class Feature(BaseModel): id: Optional[int] = None title: str description: Optional[str] = None version: Optional[str] = None status: str = 'planlagt' priority: int = 50 expected_date: Optional[date] = None completed_date: Optional[date] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class FeatureCreate(BaseModel): title: str description: Optional[str] = None version: Optional[str] = None status: str = 'planlagt' priority: int = 50 expected_date: Optional[date] = None class Idea(BaseModel): id: Optional[int] = None title: str description: Optional[str] = None category: Optional[str] = None votes: int = 0 created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class IdeaCreate(BaseModel): title: str description: Optional[str] = None category: Optional[str] = None class Workflow(BaseModel): id: Optional[int] = None title: str description: Optional[str] = None category: Optional[str] = None diagram_xml: str thumbnail_url: Optional[str] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class WorkflowCreate(BaseModel): title: str description: Optional[str] = None category: Optional[str] = None diagram_xml: str # Features/Roadmap Endpoints @router.get("/features", response_model=List[Feature]) async def get_features(version: Optional[str] = None, status: Optional[str] = None): """Get all roadmap features with optional filters""" query = "SELECT * FROM dev_features WHERE 1=1" params = [] if version: query += " AND version = %s" params.append(version) if status: query += " AND status = %s" params.append(status) query += " ORDER BY priority DESC, expected_date ASC" result = execute_query(query, tuple(params) if params else None) return result or [] @router.get("/features/{feature_id}", response_model=Feature) async def get_feature(feature_id: int): """Get a specific feature""" result = execute_query("SELECT * FROM dev_features WHERE id = %s", (feature_id,), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Feature not found") return result @router.post("/features", response_model=Feature) async def create_feature(feature: FeatureCreate): """Create a new roadmap feature""" query = """ INSERT INTO dev_features (title, description, version, status, priority, expected_date) VALUES (%s, %s, %s, %s, %s, %s) RETURNING * """ result = execute_query(query, ( feature.title, feature.description, feature.version, feature.status, feature.priority, feature.expected_date ), fetchone=True) logger.info(f"✅ Created feature: {feature.title}") return result @router.put("/features/{feature_id}", response_model=Feature) async def update_feature(feature_id: int, feature: FeatureCreate): """Update a roadmap feature""" query = """ UPDATE dev_features SET title = %s, description = %s, version = %s, status = %s, priority = %s, expected_date = %s WHERE id = %s RETURNING * """ result = execute_query(query, ( feature.title, feature.description, feature.version, feature.status, feature.priority, feature.expected_date, feature_id ), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Feature not found") logger.info(f"✅ Updated feature: {feature_id}") return result @router.delete("/features/{feature_id}") async def delete_feature(feature_id: int): """Delete a roadmap feature""" result = execute_query("DELETE FROM dev_features WHERE id = %s RETURNING id", (feature_id,), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Feature not found") logger.info(f"✅ Deleted feature: {feature_id}") return {"message": "Feature deleted successfully"} # Ideas Endpoints @router.get("/ideas", response_model=List[Idea]) async def get_ideas(category: Optional[str] = None): """Get all ideas with optional category filter""" query = "SELECT * FROM dev_ideas WHERE 1=1" params = [] if category: query += " AND category = %s" params.append(category) query += " ORDER BY votes DESC, created_at DESC" result = execute_query(query, tuple(params) if params else None) return result or [] @router.post("/ideas", response_model=Idea) async def create_idea(idea: IdeaCreate): """Create a new idea""" query = """ INSERT INTO dev_ideas (title, description, category) VALUES (%s, %s, %s) RETURNING * """ result = execute_query(query, (idea.title, idea.description, idea.category), fetchone=True) logger.info(f"✅ Created idea: {idea.title}") return result @router.post("/ideas/{idea_id}/vote") async def vote_idea(idea_id: int): """Increment vote count for an idea""" query = """ UPDATE dev_ideas SET votes = votes + 1 WHERE id = %s RETURNING * """ result = execute_query(query, (idea_id,), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Idea not found") return result @router.delete("/ideas/{idea_id}") async def delete_idea(idea_id: int): """Delete an idea""" result = execute_query("DELETE FROM dev_ideas WHERE id = %s RETURNING id", (idea_id,), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Idea not found") logger.info(f"✅ Deleted idea: {idea_id}") return {"message": "Idea deleted successfully"} # Workflows Endpoints @router.get("/workflows", response_model=List[Workflow]) async def get_workflows(category: Optional[str] = None): """Get all workflows with optional category filter""" query = "SELECT * FROM dev_workflows WHERE 1=1" params = [] if category: query += " AND category = %s" params.append(category) query += " ORDER BY created_at DESC" result = execute_query(query, tuple(params) if params else None) return result or [] @router.get("/workflows/{workflow_id}", response_model=Workflow) async def get_workflow(workflow_id: int): """Get a specific workflow""" result = execute_query("SELECT * FROM dev_workflows WHERE id = %s", (workflow_id,), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Workflow not found") return result @router.post("/workflows", response_model=Workflow) async def create_workflow(workflow: WorkflowCreate): """Create a new workflow diagram""" query = """ INSERT INTO dev_workflows (title, description, category, diagram_xml) VALUES (%s, %s, %s, %s) RETURNING * """ result = execute_query(query, ( workflow.title, workflow.description, workflow.category, workflow.diagram_xml ), fetchone=True) logger.info(f"✅ Created workflow: {workflow.title}") return result @router.put("/workflows/{workflow_id}", response_model=Workflow) async def update_workflow(workflow_id: int, workflow: WorkflowCreate): """Update a workflow diagram""" query = """ UPDATE dev_workflows SET title = %s, description = %s, category = %s, diagram_xml = %s WHERE id = %s RETURNING * """ result = execute_query(query, ( workflow.title, workflow.description, workflow.category, workflow.diagram_xml, workflow_id ), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Workflow not found") logger.info(f"✅ Updated workflow: {workflow_id}") return result @router.delete("/workflows/{workflow_id}") async def delete_workflow(workflow_id: int): """Delete a workflow""" result = execute_query("DELETE FROM dev_workflows WHERE id = %s RETURNING id", (workflow_id,), fetchone=True) if not result: raise HTTPException(status_code=404, detail="Workflow not found") logger.info(f"✅ Deleted workflow: {workflow_id}") return {"message": "Workflow deleted successfully"} # Stats endpoint @router.get("/stats") async def get_devportal_stats(): """Get DEV Portal statistics""" features_count = execute_query("SELECT COUNT(*) as count FROM dev_features", fetchone=True) ideas_count = execute_query("SELECT COUNT(*) as count FROM dev_ideas", fetchone=True) workflows_count = execute_query("SELECT COUNT(*) as count FROM dev_workflows", fetchone=True) features_by_status = execute_query(""" SELECT status, COUNT(*) as count FROM dev_features GROUP BY status """) return { "features_count": features_count['count'] if features_count else 0, "ideas_count": ideas_count['count'] if ideas_count else 0, "workflows_count": workflows_count['count'] if workflows_count else 0, "features_by_status": features_by_status or [] }