// controllers/api/v1/project.ts
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
// All Rights Reserved

import { Request, Response } from "express";

import { DtpController } from "../../../lib/controller.js";
import { IUser, ProjectStatus } from "@gadget/api";
import projectService from "../../../services/project.js";

export class ProjectApiControllerV1 extends DtpController {
  get name(): string {
    return "ProjectApiControllerV1";
  }
  get slug(): string {
    return "projectV1";
  }
  get route(): string {
    return "/projects";
  }

  constructor() {
    super();
  }

  async start(): Promise<void> {
    this.router.use(this.requireUser());

    this.router.get("/", this.getProjects.bind(this));
    this.router.post("/", this.createProject.bind(this));
    this.router.post("/pull", this.pullProject.bind(this));
    this.router.get("/:projectId", this.getProject.bind(this));
    this.router.put("/:projectId", this.updateProject.bind(this));
    this.router.delete("/:projectId", this.deleteProject.bind(this));
  }

  async getProjects(req: Request, res: Response): Promise<void> {
    try {
      const projects = await projectService.getForUser(req.user);
      res.status(200).json({
        success: true,
        data: projects,
      });
    } catch (error) {
      this.log.error("failed to get projects", { error });
      res.status(500).json({
        success: false,
        message: "failed to get projects",
      });
    }
  }

  async createProject(req: Request, res: Response): Promise<void> {
    try {
      const { name, slug, gitUrl, status } = req.body;

      if (!name || !slug) {
        res.status(400).json({
          success: false,
          message: "name and slug are required",
        });
        return;
      }

      const project = await projectService.create(req.user, {
        name,
        slug,
        gitUrl,
        status: status as ProjectStatus,
      });

      res.status(201).json({
        success: true,
        data: project,
      });
    } catch (error) {
      this.log.error("failed to create project", { error });
      res.status(500).json({
        success: false,
        message: "failed to create project",
      });
    }
  }

  async pullProject(req: Request, res: Response): Promise<void> {
    try {
      const { gitUrl } = req.body;

      if (!gitUrl || typeof gitUrl !== "string") {
        res.status(400).json({
          success: false,
          message: "gitUrl is required",
        });
        return;
      }

      // Validate the URL is parseable
      const trimmedUrl = gitUrl.trim();
      const isSshFormat = trimmedUrl.includes(":") && !trimmedUrl.startsWith("http") && !trimmedUrl.startsWith("ssh://");
      if (!isSshFormat) {
        try {
          new URL(trimmedUrl);
        } catch {
          res.status(400).json({
            success: false,
            message: "invalid git URL format",
          });
          return;
        }
      }

      const project = await projectService.createFromGitUrl(req.user, trimmedUrl);

      res.status(201).json({
        success: true,
        data: project,
      });
    } catch (error: any) {
      if (error.statusCode === 400) {
        res.status(400).json({
          success: false,
          message: error.message,
        });
        return;
      }

      // Handle duplicate gitUrl (unique partial index violation)
      if (error.code === 11000) {
        res.status(409).json({
          success: false,
          message: "a project with this git URL already exists",
        });
        return;
      }

      this.log.error("failed to pull project", { error });
      res.status(500).json({
        success: false,
        message: "failed to pull project",
      });
    }
  }

  async getProject(req: Request, res: Response): Promise<void> {
    try {
      const id = req.params.projectId as string;
      const project = await projectService.findById(id);
      if (!project) {
        res.status(404).json({
          success: false,
          message: "project not found",
        });
        return;
      }

      const user = project.user as IUser;
      if (user._id !== req.user._id) {
        res.status(403).json({
          success: false,
          message: "access denied",
        });
        return;
      }

      res.status(200).json({
        success: true,
        data: project,
      });
    } catch (error) {
      this.log.error("failed to get project", { error });
      res.status(500).json({
        success: false,
        message: "failed to get project",
      });
    }
  }

  async updateProject(req: Request, res: Response): Promise<void> {
    try {
      const id = req.params.projectId as string;
      const project = await projectService.findById(id);
      if (!project) {
        res.status(404).json({
          success: false,
          message: "project not found",
        });
        return;
      }

      const user = project.user as IUser;
      if (user._id !== req.user._id) {
        res.status(403).json({
          success: false,
          message: "access denied",
        });
        return;
      }

      const { name, slug, gitUrl, status, description, system, skills, tasks } = req.body;
      const updated = await projectService.update(project, {
        name,
        slug,
        gitUrl,
        status: status as ProjectStatus,
        description,
        system,
        skills,
        tasks,
      });

      res.status(200).json({
        success: true,
        data: updated,
      });
    } catch (error) {
      this.log.error("failed to update project", { error });
      res.status(500).json({
        success: false,
        message: "failed to update project",
      });
    }
  }

  async deleteProject(req: Request, res: Response): Promise<void> {
    try {
      const id = req.params.projectId as string;
      const project = await projectService.findById(id);
      if (!project) {
        res.status(404).json({
          success: false,
          message: "project not found",
        });
        return;
      }

      const user = project.user as IUser;
      if (user._id !== req.user._id) {
        res.status(403).json({
          success: false,
          message: "access denied",
        });
        return;
      }

      await projectService.delete(project);

      res.status(200).json({
        success: true,
        message: "project deleted",
      });
    } catch (error) {
      this.log.error("failed to delete project", { error });
      res.status(500).json({
        success: false,
        message: "failed to delete project",
      });
    }
  }
}

export default ProjectApiControllerV1;
