"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { createClient } from "@/lib/supabase/client";
import { useWorkspaceStore } from "@/stores/workspace-store";
import { useTeams } from "@/hooks/use-teams";
import { logTeamAudit } from "@/lib/team-audit";
import type {
  PermissionLevel,
  TeamResource,
  TeamRole,
  TeamRolePermission,
} from "@/types";

export const TEAM_RESOURCES: TeamResource[] = [
  "projects",
  "tasks",
  "notes",
  "calendar",
  "comments",
  "members",
];

export const PERMISSION_LEVELS: PermissionLevel[] = [
  "none",
  "view",
  "comment",
  "edit",
  "manage",
];

const PERMISSION_RANK: Record<PermissionLevel, number> = {
  none: 0,
  view: 1,
  comment: 2,
  edit: 3,
  manage: 4,
};

function getDefaultPermission(role: TeamRole, resource: TeamResource): PermissionLevel {
  if (role === "owner" || role === "admin") return "manage";
  if (role === "member" && resource === "members") return "view";
  if (role === "member" && resource === "comments") return "comment";
  if (role === "member") return "edit";
  if (role === "viewer" && resource === "comments") return "comment";
  if (role === "viewer" && resource !== "members") return "view";
  return "none";
}

function normalizeMatrix(rows: TeamRolePermission[]) {
  const matrix = new Map<string, PermissionLevel>();

  rows.forEach((row) => {
    matrix.set(`${row.role}:${row.resource}`, row.access_level);
  });

  return matrix;
}

export function useTeamPermissions(teamId?: string | null) {
  const activeTeamId = useWorkspaceStore((state) => state.activeTeamId);
  const initialized = useWorkspaceStore((state) => state.initialized);
  const resolvedTeamId = teamId === undefined ? activeTeamId : teamId;
  const { activeRole, userId } = useTeams();
  const [permissions, setPermissions] = useState<TeamRolePermission[]>([]);
  const [loading, setLoading] = useState(true);
  const supabase = createClient();

  const fetchPermissions = useCallback(async () => {
    if (!initialized) return;

    if (!resolvedTeamId) {
      setPermissions([]);
      setLoading(false);
      return;
    }

    setLoading(true);

    const { data, error } = await supabase
      .from("team_role_permissions")
      .select("*")
      .eq("team_id", resolvedTeamId);

    if (error) {
      console.error("Failed to load team permissions", error);
      setLoading(false);
      return;
    }

    setPermissions((data || []) as TeamRolePermission[]);
    setLoading(false);
  }, [initialized, resolvedTeamId, supabase]);

  useEffect(() => {
    const timer = window.setTimeout(() => {
      void fetchPermissions();
    }, 0);

    return () => window.clearTimeout(timer);
  }, [fetchPermissions]);

  useEffect(() => {
    if (!resolvedTeamId) return;

    const channelName = `team-role-permissions:${resolvedTeamId}:${Math.random()
      .toString(36)
      .slice(2, 8)}`;
    const channel = supabase
      .channel(channelName)
      .on(
        "postgres_changes",
        {
          event: "*",
          schema: "public",
          table: "team_role_permissions",
          filter: `team_id=eq.${resolvedTeamId}`,
        },
        () => {
          void fetchPermissions();
        }
      )
      .subscribe();

    return () => {
      void supabase.removeChannel(channel);
    };
  }, [fetchPermissions, resolvedTeamId, supabase]);

  const matrix = useMemo(() => normalizeMatrix(permissions), [permissions]);

  function getPermissionForRole(role: TeamRole, resource: TeamResource): PermissionLevel {
    if (role === "owner") return "manage";
    return matrix.get(`${role}:${resource}`) || getDefaultPermission(role, resource);
  }

  function can(resource: TeamResource, requiredLevel: PermissionLevel = "view") {
    if (!resolvedTeamId) return true;
    if (activeRole === "owner") return true;
    const level = activeRole ? getPermissionForRole(activeRole, resource) : "none";
    return PERMISSION_RANK[level] >= PERMISSION_RANK[requiredLevel];
  }

  async function updatePermission(
    role: TeamRole,
    resource: TeamResource,
    accessLevel: PermissionLevel
  ) {
    if (!resolvedTeamId) return;

    const { error } = await supabase.from("team_role_permissions").upsert({
      team_id: resolvedTeamId,
      role,
      resource,
      access_level: accessLevel,
    });

    if (error) throw error;

    await logTeamAudit(supabase, {
      teamId: resolvedTeamId,
      actorId: userId,
      action: "permission_updated",
      entityType: "team",
      title: `${role} permission updated`,
      details: {
        role,
        resource,
        access_level: accessLevel,
      },
    });

    await fetchPermissions();
  }

  return {
    permissions,
    loading,
    can,
    getPermissionForRole,
    updatePermission,
    refetch: fetchPermissions,
  };
}
