import { z } from "zod";
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { endOfMonth, startOfMonth, subMonths } from "date-fns";
import { auth } from "@/auth";
import { prisma } from "@/lib/prisma";

import { createWorkspaceSchema, updateWorkspaceSchema } from "../schemas";

// Define enum values as constants
const MemberRole = {
  ADMIN: 'ADMIN' as const,
  MEMBER: 'MEMBER' as const
};

const TaskStatus = {
  BACKLOG: 'BACKLOG' as const,
  TODO: 'TODO' as const,
  IN_PROGRESS: 'IN_PROGRESS' as const,
  IN_REVIEW: 'IN_REVIEW' as const,
  DONE: 'DONE' as const
};

// Helper function to safely check if value is a File
const isFile = (value: unknown): value is File => {
  if (typeof File === 'undefined') {
    // During build or in environments without File API
    return !!(value && typeof value === 'object' && value !== null && 'arrayBuffer' in value);
  }
  return value instanceof File;
};

function generateInviteCode(length: number) {
  const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let result = "";
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * characters.length));
  }
  return result;
}

const app = new Hono()
  .get("/", async (c) => {
    const session = await auth();

    console.log("Workspaces API - Session:", session?.user);

    if (!session?.user?.email) {
      console.log("Workspaces API - No session or email");
      return c.json({ error: "Unauthorized" }, 401);
    }

    const currentUser = await prisma.user.findUnique({
      where: { email: session.user.email },
    });

    if (!currentUser) {
      console.log("Workspaces API - User not found:", session.user.email);
      return c.json({ error: "User not found" }, 404);
    }

    console.log("Workspaces API - Found user:", currentUser.id);

    // Find all memberships for the user
    const memberships = await prisma.member.findMany({
      where: { userId: currentUser.id },
      include: { workspace: true },
      orderBy: { createdAt: 'desc' }
    });

    console.log("Workspaces API - Found memberships:", memberships.length);

    if (memberships.length === 0) {
      return c.json({ data: { documents: [], total: 0 } });
    }

    // Extract workspaces from memberships and sort by most recently updated
    const workspaces = memberships
      .map((membership) => membership.workspace)
      .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());

    console.log("Workspaces API - Returning workspaces:", workspaces.length);

    return c.json({
      data: {
        documents: workspaces,
        total: workspaces.length,
      },
    });
  })
  .get("/:workspaceId", async (c) => {
    const session = await auth();
    const { workspaceId } = c.req.param();

    if (!session?.user?.email) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    const currentUser = await prisma.user.findUnique({
      where: { email: session.user.email },
    });

    if (!currentUser) {
      return c.json({ error: "User not found" }, 404);
    }

    // Check if user is a member of the workspace
    const member = await prisma.member.findFirst({
      where: {
        workspaceId,
        userId: currentUser.id,
      },
    });

    if (!member) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    // Get the workspace
    const workspace = await prisma.workspace.findUnique({
      where: { id: workspaceId },
    });

    if (!workspace) {
      return c.json({ error: "Workspace not found" }, 404);
    }

    return c.json({ data: workspace });
  })
  .get("/:workspaceId/info", async (c) => {
    const session = await auth();
    const { workspaceId } = c.req.param();

    if (!session?.user?.email) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    // Get the workspace
    const workspace = await prisma.workspace.findUnique({
      where: { id: workspaceId },
    });

    if (!workspace) {
      return c.json({ error: "Workspace not found" }, 404);
    }

    return c.json({
      data: {
        id: workspace.id,
        name: workspace.name,
        imageUrl: workspace.imageUrl,
      },
    });
  })
  .post(
    "/",
    zValidator("form", createWorkspaceSchema),
    async (c) => {
      console.log("🚀 WORKSPACE CREATE: Starting workspace creation...");
      
      try {
        const session = await auth();
        console.log("🚀 WORKSPACE CREATE: Session obtained:", !!session?.user?.email);
        console.log("🚀 WORKSPACE CREATE: Session user ID:", session?.user?.id);

        const { name, image } = c.req.valid("form");
        console.log("🚀 WORKSPACE CREATE: Form data:", { name, hasImage: !!image });

        if (!session?.user?.email) {
          console.log("❌ WORKSPACE CREATE: No session or email");
          return c.json({ error: "Unauthorized" }, 401);
        }

        console.log("🚀 WORKSPACE CREATE: Looking up user by email:", session.user.email);
        
        // Check for duplicate users with same email
        const allUsersWithEmail = await prisma.user.findMany({
          where: { email: session.user.email },
        });
        
        console.log("🚀 WORKSPACE CREATE: Found users with this email:", allUsersWithEmail.map((u: any) => ({ id: u.id, email: u.email, name: u.name })));
        
        // Try to find user by session ID first
        let currentUser = await prisma.user.findUnique({
          where: { id: session.user.id },
        });
        
        console.log("🚀 WORKSPACE CREATE: User by session ID:", currentUser ? { id: currentUser.id, email: currentUser.email } : "Not found");
        
        // If not found by session ID, use email lookup (first match)
        if (!currentUser) {
          console.log("🚀 WORKSPACE CREATE: Session ID not found, using email lookup");
          currentUser = await prisma.user.findUnique({
            where: { email: session.user.email },
          });
        }

        if (!currentUser) {
          console.log("❌ WORKSPACE CREATE: User not found by either ID or email");
          return c.json({ error: "User not found" }, 404);
        }

        console.log("🚀 WORKSPACE CREATE: Using user:", { id: currentUser.id, email: currentUser.email });

        // Handle image upload
        let uploadedImageUrl = "";
        
        console.log("🚀 WORKSPACE CREATE: Processing image...");
        if (isFile(image)) {
          console.log("🚀 WORKSPACE CREATE: Converting file to base64");
          // Convert file to base64 for storage
          const buffer = await image.arrayBuffer();
          const base64 = Buffer.from(buffer).toString('base64');
          uploadedImageUrl = `data:${image.type};base64,${base64}`;
          console.log("🚀 WORKSPACE CREATE: Image converted, size:", base64.length);
        } else if (typeof image === "string" && image) {
          uploadedImageUrl = image;
          console.log("🚀 WORKSPACE CREATE: Using string image");
        } else {
          console.log("🚀 WORKSPACE CREATE: No image provided");
        }

        console.log("🚀 WORKSPACE CREATE: Starting database transaction...");
        // Create the workspace and add the user as an admin member
        const workspace = await prisma.$transaction(async (tx: any) => {
          console.log("🚀 WORKSPACE CREATE: Creating workspace...");
          
          // Create workspace
          const workspace = await tx.workspace.create({
            data: {
              name,
              userId: currentUser.id,
              imageUrl: uploadedImageUrl,
              inviteCode: generateInviteCode(6),
            },
          });

          console.log("🚀 WORKSPACE CREATE: Workspace created:", { id: workspace.id, name: workspace.name });

          console.log("🚀 WORKSPACE CREATE: Adding user as admin member...");
          // Add user as admin member
          await tx.member.create({
            data: {
              userId: currentUser.id,
              workspaceId: workspace.id,
              role: MemberRole.ADMIN,
            },
          });

          console.log("🚀 WORKSPACE CREATE: Admin member created");
          return workspace;
        });

        console.log("✅ WORKSPACE CREATE: Transaction completed successfully:", { workspaceId: workspace.id });
        return c.json({ data: workspace });
        
      } catch (error) {
        console.error("❌ WORKSPACE CREATE: Error occurred:", error);
        console.error("❌ WORKSPACE CREATE: Error stack:", error instanceof Error ? error.stack : 'No stack trace');
        
        // Return more specific error information
        if (error instanceof Error) {
          return c.json({ 
            error: "Failed to create workspace", 
            details: error.message,
            code: error.name 
          }, 500);
        }
        
        return c.json({ error: "Failed to create workspace", details: "Unknown error" }, 500);
      }
    }
  )
  .patch(
    "/:workspaceId",
    zValidator("form", updateWorkspaceSchema),
    async (c) => {
      const session = await auth();
      const { workspaceId } = c.req.param();
      const { name, image } = c.req.valid("form");

      if (!session?.user?.email) {
        return c.json({ error: "Unauthorized" }, 401);
      }

      const currentUser = await prisma.user.findUnique({
        where: { email: session.user.email },
      });

      if (!currentUser) {
        return c.json({ error: "User not found" }, 404);
      }

      // Check if user is an admin of the workspace
      const member = await prisma.member.findFirst({
        where: {
          workspaceId,
          userId: currentUser.id,
          role: MemberRole.ADMIN,
        },
      });

      if (!member) {
        return c.json({ error: "Unauthorized" }, 401);
      }

      // Get the existing workspace
      const existingWorkspace = await prisma.workspace.findUnique({
        where: { id: workspaceId },
      });

      if (!existingWorkspace) {
        return c.json({ error: "Workspace not found" }, 404);
      }

      // Handle image upload
      let uploadedImageUrl = existingWorkspace.imageUrl;
      
      if (isFile(image)) {
        // Convert file to base64 for storage
        const buffer = await image.arrayBuffer();
        const base64 = Buffer.from(buffer).toString('base64');
        uploadedImageUrl = `data:${image.type};base64,${base64}`;
      } else if (typeof image === "string" && image) {
        uploadedImageUrl = image;
      }

      // Update the workspace
      const workspace = await prisma.workspace.update({
        where: { id: workspaceId },
        data: {
          name: name || existingWorkspace.name,
          imageUrl: uploadedImageUrl,
        },
      });

      return c.json({ data: workspace });
    }
  )
  .delete("/:workspaceId", async (c) => {
    const session = await auth();
    const { workspaceId } = c.req.param();

    if (!session?.user?.email) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    const currentUser = await prisma.user.findUnique({
      where: { email: session.user.email },
    });

    if (!currentUser) {
      return c.json({ error: "User not found" }, 404);
    }

    // Check if user is an admin of the workspace
    const member = await prisma.member.findFirst({
      where: {
        workspaceId,
        userId: currentUser.id,
        role: MemberRole.ADMIN,
      },
    });

    if (!member) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    // Delete the workspace and all related data in a transaction
    await prisma.$transaction(async (tx: any) => {
      // Find all projects in the workspace
      const projects = await tx.project.findMany({
        where: { workspaceId },
        select: { id: true },
      });
      
      const projectIds = projects.map((project: any) => project.id);

      // Delete all tasks in the projects
      await tx.task.deleteMany({
        where: {
          projectId: {
            in: projectIds,
          },
        },
      });

      // Delete all tasks directly in the workspace (not in projects)
      await tx.task.deleteMany({
        where: {
          workspaceId,
          projectId: null,
        },
      });

      // Delete all projects
      await tx.project.deleteMany({
        where: { workspaceId },
      });

      // Delete all members
      await tx.member.deleteMany({
        where: { workspaceId },
      });

      // Finally, delete the workspace
      await tx.workspace.delete({
        where: { id: workspaceId },
      });
    });

    return c.json({ data: { id: workspaceId } });
  })
  .post("/:workspaceId/reset-invite-code", async (c) => {
    const session = await auth();
    const { workspaceId } = c.req.param();

    if (!session?.user?.email) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    const currentUser = await prisma.user.findUnique({
      where: { email: session.user.email },
    });

    if (!currentUser) {
      return c.json({ error: "User not found" }, 404);
    }

    // Check if user is an admin of the workspace
    const member = await prisma.member.findFirst({
      where: {
        workspaceId,
        userId: currentUser.id,
        role: MemberRole.ADMIN,
      },
    });

    if (!member) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    // Update the invite code
    const workspace = await prisma.workspace.update({
      where: { id: workspaceId },
      data: {
        inviteCode: generateInviteCode(6),
      },
    });

    return c.json({ data: workspace });
  })
  .post(
    "/:workspaceId/join",
    zValidator("json", z.object({ code: z.string() })),
    async (c) => {
      const session = await auth();
      const { workspaceId } = c.req.param();
      const { code } = c.req.valid("json");

      if (!session?.user?.email) {
        return c.json({ error: "Unauthorized" }, 401);
      }

      const currentUser = await prisma.user.findUnique({
        where: { email: session.user.email },
      });

      if (!currentUser) {
        return c.json({ error: "User not found" }, 404);
      }

      // Check if user is already a member
      const existingMember = await prisma.member.findFirst({
        where: {
          workspaceId,
          userId: currentUser.id,
        },
      });

      if (existingMember) {
        return c.json({ error: "Already a member" }, 400);
      }

      // Get the workspace
      const workspace = await prisma.workspace.findUnique({
        where: { id: workspaceId },
      });

      if (!workspace) {
        return c.json({ error: "Workspace not found" }, 404);
      }

      // Verify invite code
      if (workspace.inviteCode !== code) {
        return c.json({ error: "Invalid invite code" }, 400);
      }

      // Add user as a member
      await prisma.member.create({
        data: {
          workspaceId,
          userId: currentUser.id,
          role: MemberRole.MEMBER,
        },
      });

      return c.json({ data: workspace });
    }
  )
  .get("/:workspaceId/labels", async (c) => {
    const session = await auth();
    const { workspaceId } = c.req.param();

    if (!session?.user?.email) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    const currentUser = await prisma.user.findUnique({
      where: { email: session.user.email },
    });

    if (!currentUser) {
      return c.json({ error: "User not found" }, 404);
    }

    // Check if user is a member of the workspace
    const member = await prisma.member.findFirst({
      where: {
        workspaceId,
        userId: currentUser.id,
      },
    });

    if (!member) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    // Get all unique labels from workspace tasks
    const tasks = await prisma.task.findMany({
      where: { workspaceId },
      select: { labels: true },
    });

    // Extract unique labels
    const allLabels = tasks.flatMap((task: any) => task.labels || []);
    const uniqueLabels = Array.from(new Set(allLabels)).sort();

    return c.json({ data: uniqueLabels });
  })
  .get("/:workspaceId/analytics", async (c) => {
    const session = await auth();
    const { workspaceId } = c.req.param();

    if (!session?.user?.email) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    const currentUser = await prisma.user.findUnique({
      where: { email: session.user.email },
    });

    if (!currentUser) {
      return c.json({ error: "User not found" }, 404);
    }

    // Check if user is a member of the workspace
    const member = await prisma.member.findFirst({
      where: {
        workspaceId,
        userId: currentUser.id,
      },
    });

    if (!member) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    const now = new Date();
    const thisMonthStart = startOfMonth(now);
    const thisMonthEnd = endOfMonth(now);
    const lastMonthStart = startOfMonth(subMonths(now, 1));
    const lastMonthEnd = endOfMonth(subMonths(now, 1));

    // This month tasks
    const thisMonthTasks = await prisma.task.count({
      where: {
        workspaceId,
        createdAt: {
          gte: thisMonthStart,
          lte: thisMonthEnd,
        },
      },
    });

    // Last month tasks
    const lastMonthTasks = await prisma.task.count({
      where: {
        workspaceId,
        createdAt: {
          gte: lastMonthStart,
          lte: lastMonthEnd,
        },
      },
    });

    const taskCount = thisMonthTasks;
    const taskDifference = taskCount - lastMonthTasks;

    // This month assigned tasks
    const thisMonthAssignedTasks = await prisma.task.count({
      where: {
        workspaceId,
        assigneeId: member.id,
        createdAt: {
          gte: thisMonthStart,
          lte: thisMonthEnd,
        },
      },
    });

    // Last month assigned tasks
    const lastMonthAssignedTasks = await prisma.task.count({
      where: {
        workspaceId,
        assigneeId: member.id,
        createdAt: {
          gte: lastMonthStart,
          lte: lastMonthEnd,
        },
      },
    });

    const assignedTaskCount = thisMonthAssignedTasks;
    const assignedTaskDifference = assignedTaskCount - lastMonthAssignedTasks;

    // This month incomplete tasks
    const thisMonthIncompleteTasks = await prisma.task.count({
      where: {
        workspaceId,
        status: {
          not: TaskStatus.DONE,
        },
        createdAt: {
          gte: thisMonthStart,
          lte: thisMonthEnd,
        },
      },
    });

    // Last month incomplete tasks
    const lastMonthIncompleteTasks = await prisma.task.count({
      where: {
        workspaceId,
        status: {
          not: TaskStatus.DONE,
        },
        createdAt: {
          gte: lastMonthStart,
          lte: lastMonthEnd,
        },
      },
    });

    const incompleteTaskCount = thisMonthIncompleteTasks;
    const incompleteTaskDifference = incompleteTaskCount - lastMonthIncompleteTasks;

    // This month completed tasks
    const thisMonthCompletedTasks = await prisma.task.count({
      where: {
        workspaceId,
        status: TaskStatus.DONE,
        createdAt: {
          gte: thisMonthStart,
          lte: thisMonthEnd,
        },
      },
    });

    // Last month completed tasks
    const lastMonthCompletedTasks = await prisma.task.count({
      where: {
        workspaceId,
        status: TaskStatus.DONE,
        createdAt: {
          gte: lastMonthStart,
          lte: lastMonthEnd,
        },
      },
    });

    const completedTaskCount = thisMonthCompletedTasks;
    const completedTaskDifference = completedTaskCount - lastMonthCompletedTasks;

    // This month overdue tasks
    const thisMonthOverDueTasks = await prisma.task.count({
      where: {
        workspaceId,
        status: {
          not: TaskStatus.DONE,
        },
        dueDate: {
          lt: now,
        },
        createdAt: {
          gte: thisMonthStart,
          lte: thisMonthEnd,
        },
      },
    });

    // Last month overdue tasks
    const lastMonthOverDueTasks = await prisma.task.count({
      where: {
        workspaceId,
        status: {
          not: TaskStatus.DONE,
        },
        dueDate: {
          lt: now,
        },
        createdAt: {
          gte: lastMonthStart,
          lte: lastMonthEnd,
        },
      },
    });

    const overdueTaskCount = thisMonthOverDueTasks;
    const overdueTaskDifference = overdueTaskCount - lastMonthOverDueTasks;

    // Communication Activity Stats
    // Total comments in workspace
    const totalComments = await prisma.comment.count({
      where: {
        task: {
          workspaceId,
        },
      },
    });

    // This month comments
    const thisMonthComments = await prisma.comment.count({
      where: {
        task: {
          workspaceId,
        },
        createdAt: {
          gte: thisMonthStart,
          lte: thisMonthEnd,
        },
      },
    });

    // Last month comments
    const lastMonthComments = await prisma.comment.count({
      where: {
        task: {
          workspaceId,
        },
        createdAt: {
          gte: lastMonthStart,
          lte: lastMonthEnd,
        },
      },
    });

    const commentsDifference = thisMonthComments - lastMonthComments;

    // Tasks with comments count
    const tasksWithComments = await prisma.task.count({
      where: {
        workspaceId,
        comments: {
          some: {},
        },
      },
    });

    // Total tasks count for calculating percentage
    const totalTasksInWorkspace = await prisma.task.count({
      where: {
        workspaceId,
      },
    });

    // Calculate average comments per task
    const avgCommentsPerTask = totalTasksInWorkspace > 0 
      ? parseFloat((totalComments / totalTasksInWorkspace).toFixed(1))
      : 0;

    return c.json({
      data: {
        taskCount,
        taskDifference,
        assignedTaskCount,
        assignedTaskDifference,
        completedTaskCount,
        completedTaskDifference,
        incompleteTaskCount,
        incompleteTaskDifference,
        overdueTaskCount,
        overdueTaskDifference,
        // Communication Activity
        totalComments,
        thisMonthComments,
        commentsDifference,
        tasksWithComments,
        totalTasksInWorkspace,
        avgCommentsPerTask,
      },
    });
  });

export default app;
