"use client";

import { useCallback, useEffect, useState } from "react";
import { createClient, getBrowserUserId } from "@/lib/supabase/client";
import { logTeamAudit } from "@/lib/team-audit";
import type { Comment, Profile } from "@/types";

interface UseCommentsOptions {
  entityType: "task" | "note";
  entityId: string;
  teamId: string | null;
}

export function useComments({ entityType, entityId, teamId }: UseCommentsOptions) {
  const [comments, setComments] = useState<Comment[]>([]);
  const [loading, setLoading] = useState(true);
  const [userId, setUserId] = useState<string | null>(null);
  const supabase = createClient();

  useEffect(() => {
    void getBrowserUserId().then(setUserId).catch(() => setUserId(null));
  }, []);

  async function requireCurrentUserId() {
    const currentUserId = userId || (await getBrowserUserId());
    if (currentUserId && currentUserId !== userId) {
      setUserId(currentUserId);
    }
    return currentUserId;
  }

  const fetchComments = useCallback(async () => {
    if (!entityId) {
      setComments([]);
      setLoading(false);
      return;
    }

    setLoading(true);

    const { data, error } = await supabase
      .from("comments")
      .select("*")
      .eq("entity_type", entityType)
      .eq("entity_id", entityId)
      .order("created_at");

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

    const rawComments = (data || []) as Comment[];
    const profileIds = Array.from(
      new Set(
        rawComments.flatMap((comment) => [
          comment.user_id,
          ...(comment.mentioned_user_ids || []),
        ])
      )
    );

    let profileMap = new Map<string, Profile>();
    if (profileIds.length > 0) {
      const { data: profilesData } = await supabase
        .from("profiles")
        .select("id, email, full_name, avatar_url, created_at, updated_at")
        .in("id", profileIds);

      profileMap = new Map(
        ((profilesData || []) as Profile[]).map((profile) => [profile.id, profile])
      );
    }

    setComments(
      rawComments.map((comment) => ({
        ...comment,
        author: profileMap.get(comment.user_id) || null,
        mentioned_users: (comment.mentioned_user_ids || [])
          .map((profileId) => profileMap.get(profileId))
          .filter(Boolean) as Profile[],
      }))
    );
    setLoading(false);
  }, [entityId, entityType, supabase]);

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

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

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

    const channelName = `comments:${entityType}:${entityId}:${Math.random()
      .toString(36)
      .slice(2, 8)}`;
    const channel = supabase
      .channel(channelName)
      .on(
        "postgres_changes",
        {
          event: "*",
          schema: "public",
          table: "comments",
        },
        (payload) => {
          const next = payload.new as Partial<Comment>;
          const previous = payload.old as Partial<Comment>;
          const matches =
            (next.entity_id === entityId && next.entity_type === entityType) ||
            (previous.entity_id === entityId && previous.entity_type === entityType);

          if (matches) {
            void fetchComments();
          }
        }
      )
      .subscribe();

    return () => {
      void supabase.removeChannel(channel);
    };
  }, [entityId, entityType, fetchComments, supabase]);

  async function createMentionNotifications(
    actorId: string,
    commentId: string,
    body: string,
    mentionIds: string[],
    previousMentionIds: string[] = []
  ) {
    const newMentionIds = mentionIds.filter(
      (mentionedId) => mentionedId !== actorId && !previousMentionIds.includes(mentionedId)
    );

    if (newMentionIds.length === 0) return;

    const targetLabel = entityType === "note" ? "note" : "task";
    const link = entityType === "note" ? `/notes/${entityId}` : "/tasks";

    const { error } = await supabase.from("notifications").insert(
      newMentionIds.map((mentionedId) => ({
        user_id: mentionedId,
        actor_id: actorId,
        team_id: teamId,
        kind: "mention",
        title: `You were mentioned in a ${targetLabel}`,
        body: body.slice(0, 160),
        link,
        details: {
          comment_id: commentId,
          entity_type: entityType,
          entity_id: entityId,
        },
      }))
    );

    if (error) {
      console.error("Failed to create mention notifications", error);
    }
  }

  async function createComment(input: {
    body: string;
    mentionedUserIds?: string[];
  }) {
    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");

    const { data, error } = await supabase
      .from("comments")
      .insert({
        user_id: currentUserId,
        team_id: teamId,
        entity_type: entityType,
        entity_id: entityId,
        body: input.body.trim(),
        mentioned_user_ids: input.mentionedUserIds || [],
      })
      .select()
      .single();

    if (error) throw error;

    await createMentionNotifications(
      currentUserId,
      data.id,
      input.body.trim(),
      input.mentionedUserIds || []
    );

    await logTeamAudit(supabase, {
      teamId,
      actorId: currentUserId,
      action: "comment_created",
      entityType: "comment",
      entityId: data.id,
      title: input.body.trim().slice(0, 80) || "Comment created",
      details: {
        comment_on: entityType,
        target_id: entityId,
        mentions: input.mentionedUserIds || [],
      },
    });

    await fetchComments();
    return data as Comment;
  }

  async function updateComment(
    id: string,
    input: { body: string; mentionedUserIds?: string[] }
  ) {
    const existing = comments.find((comment) => comment.id === id);
    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");
    const { error } = await supabase
      .from("comments")
      .update({
        body: input.body.trim(),
        mentioned_user_ids: input.mentionedUserIds || [],
      })
      .eq("id", id);

    if (error) throw error;

    await createMentionNotifications(
      currentUserId,
      id,
      input.body.trim(),
      input.mentionedUserIds || [],
      existing?.mentioned_user_ids || []
    );

    await logTeamAudit(supabase, {
      teamId,
      actorId: currentUserId,
      action: "comment_updated",
      entityType: "comment",
      entityId: id,
      title: input.body.trim().slice(0, 80) || "Comment updated",
      details: {
        comment_on: entityType,
        target_id: entityId,
        mentions: input.mentionedUserIds || [],
      },
    });

    await fetchComments();
  }

  async function deleteComment(id: string) {
    const existing = comments.find((comment) => comment.id === id);
    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");
    const { error } = await supabase.from("comments").delete().eq("id", id);
    if (error) throw error;

    await logTeamAudit(supabase, {
      teamId,
      actorId: currentUserId,
      action: "comment_deleted",
      entityType: "comment",
      entityId: id,
      title: existing?.body.slice(0, 80) || "Comment deleted",
      details: {
        comment_on: entityType,
        target_id: entityId,
      },
    });

    await fetchComments();
  }

  return {
    comments,
    loading,
    userId,
    createComment,
    updateComment,
    deleteComment,
    refetch: fetchComments,
  };
}
