import { z } from "zod";
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { auth } from "@/auth";
import { prisma } from "@/lib/prisma";
import { MemberRole } from "@prisma/client";
import { createWorkspaceAddedNotification } from "@/lib/notifications";
import { emitNotification } from "@/lib/socket";

const app = new Hono()
  .get(
    "/",
    zValidator("query", z.object({ workspaceId: z.string() })),
    async (c) => {
      const session = await auth();
      const { workspaceId } = c.req.valid("query");

      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 members of the workspace with their user information
      const members = await prisma.member.findMany({
        where: { workspaceId },
        include: {
          user: {
            select: {
              id: true,
              name: true,
              email: true,
              image: true,
            },
          },
        },
      });

      // Format the response to match the expected structure
      const formattedMembers = members.map(member => ({
        id: member.id,
        workspaceId: member.workspaceId,
        userId: member.userId,
        role: member.role,
        name: member.user.name || member.user.email,
        email: member.user.email,
        imageUrl: member.user.image,
        createdAt: member.createdAt,
        updatedAt: member.updatedAt
      }));

      return c.json({
        data: {
          total: formattedMembers.length,
          documents: formattedMembers,
        },
      });
    }
  )
  .get(
    "/available",
    zValidator("query", z.object({ workspaceId: z.string() })),
    async (c) => {
      const session = await auth();
      const { workspaceId } = c.req.valid("query");

      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 members of the workspace
      const existingMembers = await prisma.member.findMany({
        where: { workspaceId },
        select: { userId: true }
      });

      const existingMemberIds = existingMembers.map(m => m.userId);

      // Get all users that are not members of the workspace
      const availableUsers = await prisma.user.findMany({
        where: {
          id: { notIn: existingMemberIds }
        },
        select: {
          id: true,
          name: true,
          email: true,
          image: true,
        }
      });

      return c.json({
        data: {
          total: availableUsers.length,
          documents: availableUsers,
        },
      });
    }
  )
  .get(
    "/current",
    zValidator("query", z.object({ workspaceId: z.string() })),
    async (c) => {
      const session = await auth();
      const { workspaceId } = c.req.valid("query");

      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);
      }

      // Get current user's member info
      const member = await prisma.member.findFirst({
        where: {
          workspaceId,
          userId: currentUser.id,
        }
      });

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

      return c.json({
        data: {
          id: member.id,
          role: member.role,
          userId: member.userId,
        },
      });
    }
  )
  .post(
    "/",
    zValidator("json", z.object({ 
      workspaceId: z.string(),
      userId: z.string(),
      role: z.nativeEnum(MemberRole).default(MemberRole.MEMBER)
    })),
    async (c) => {
      const session = await auth();
      const { workspaceId, userId, role } = 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 current user is an admin of the workspace
      const currentMember = await prisma.member.findFirst({
        where: {
          workspaceId,
          userId: currentUser.id,
          role: MemberRole.ADMIN
        }
      });

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

      // Check if user to add exists
      const userToAdd = await prisma.user.findUnique({
        where: { id: userId }
      });

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

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

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

      // Add the user as a member
      const newMember = await prisma.member.create({
        data: {
          workspaceId,
          userId,
          role
        },
        include: {
          user: {
            select: {
              name: true,
              email: true,
              image: true
            }
          },
          workspace: {
            select: {
              name: true
            }
          }
        }
      });

      // Create workspace addition notification
      try {
        const notification = await createWorkspaceAddedNotification(
          userId,
          workspaceId,
          newMember.workspace.name,
          currentUser.name || currentUser.email
        );

        if (notification) {
          await emitNotification(notification.userId, notification);
        }
      } catch (error) {
        console.error('Failed to create workspace addition notification:', error);
      }

      return c.json({ 
        data: {
          id: newMember.id,
          workspaceId: newMember.workspaceId,
          userId: newMember.userId,
          role: newMember.role,
          name: newMember.user.name || newMember.user.email,
          email: newMember.user.email,
          imageUrl: newMember.user.image,
          createdAt: newMember.createdAt,
          updatedAt: newMember.updatedAt
        } 
      });
    }
  )
  .delete("/:memberId", async (c) => {
    const session = await auth();
    const { memberId } = 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);
    }

    // Get the member to delete with workspace info
    const memberToDelete = await prisma.member.findUnique({
      where: { id: memberId },
      include: {
        workspace: true
      }
    });

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

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

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

    // Check permissions (admin or self-deletion)
    const isSelfDeletion = currentMember.id === memberToDelete.id;
    const isAdmin = currentMember.role === MemberRole.ADMIN;
    
    if (!isSelfDeletion && !isAdmin) {
      return c.json({ error: "Unauthorized" }, 401);
    }

    // Prevent deleting the workspace owner
    if (memberToDelete.workspace.userId === memberToDelete.userId) {
      return c.json({ error: "Cannot delete workspace owner" }, 400);
    }

    // Check if this is the last admin (if deleting an admin)
    if (memberToDelete.role === MemberRole.ADMIN) {
      const adminCount = await prisma.member.count({
        where: { 
          workspaceId: memberToDelete.workspaceId,
          role: MemberRole.ADMIN,
          id: { not: memberId } // Exclude the member being deleted
        },
      });

      if (adminCount === 0) {
        return c.json({ error: "Cannot delete the only admin" }, 400);
      }
    }

    // Delete the member
    await prisma.member.delete({
      where: { id: memberId },
    });

    return c.json({ data: { id: memberToDelete.id } });
  })
  .patch(
    "/:memberId",
    zValidator("json", z.object({ role: z.nativeEnum(MemberRole) })),
    async (c) => {
      const session = await auth();
      const { memberId } = c.req.param();
      const { role } = 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);
      }

      // Get the member to update
      const memberToUpdate = await prisma.member.findUnique({
        where: { id: memberId },
      });

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

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

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

      // Check if current user is admin
      if (currentMember.role !== MemberRole.ADMIN) {
        return c.json({ error: "Unauthorized" }, 401);
      }

      // If downgrading from ADMIN, check if there's at least one other admin
      if (memberToUpdate.role === MemberRole.ADMIN && role === MemberRole.MEMBER) {
        const adminCount = await prisma.member.count({
          where: { 
            workspaceId: memberToUpdate.workspaceId,
            role: MemberRole.ADMIN
          },
        });

        if (adminCount === 1) {
          return c.json({ error: "Cannot downgrade the only admin" }, 400);
        }
      }

      // Update the member
      const updatedMember = await prisma.member.update({
        where: { id: memberId },
        data: { role },
      });

      return c.json({ data: { id: updatedMember.id } });
    }
  );

export default app;
