"use client";

import { useCallback, useEffect, useState } from "react";
import { useWorkspaceStore } from "@/stores/workspace-store";
import type {
  CalendarFeedToken,
  GoogleCalendarCalendar,
  GmailMessageSummary,
  GoogleDriveFileSummary,
  GitHubRepository,
  IntegrationConnection,
  IntegrationDelivery,
  WebhookEventType,
} from "@/types";

interface CreateSlackConnectionInput {
  name: string;
  webhookUrl: string;
  eventTypes: WebhookEventType[];
}

interface CreateCalendarFeedInput {
  name: string;
}

interface CreateGitHubConnectionInput {
  name: string;
  token: string;
}

export function useIntegrations() {
  const activeTeamId = useWorkspaceStore((state) => state.activeTeamId);
  const initialized = useWorkspaceStore((state) => state.initialized);
  const [slackConnections, setSlackConnections] = useState<IntegrationConnection[]>([]);
  const [googleConnections, setGoogleConnections] = useState<IntegrationConnection[]>([]);
  const [gmailConnections, setGmailConnections] = useState<IntegrationConnection[]>([]);
  const [driveConnections, setDriveConnections] = useState<IntegrationConnection[]>([]);
  const [githubConnections, setGitHubConnections] = useState<IntegrationConnection[]>([]);
  const [telegramConnections, setTelegramConnections] = useState<IntegrationConnection[]>([]);
  const [sheetsConnections, setSheetsConnections] = useState<IntegrationConnection[]>([]);
  const [notionConnections, setNotionConnections] = useState<IntegrationConnection[]>([]);
  const [calendarFeeds, setCalendarFeeds] = useState<CalendarFeedToken[]>([]);
  const [googleCalendarsByConnection, setGoogleCalendarsByConnection] = useState<
    Record<string, GoogleCalendarCalendar[]>
  >({});
  const [githubReposByConnection, setGitHubReposByConnection] = useState<
    Record<string, GitHubRepository[]>
  >({});
  const [gmailMessagesByConnection, setGmailMessagesByConnection] = useState<
    Record<string, GmailMessageSummary[]>
  >({});
  const [driveFilesByConnection, setDriveFilesByConnection] = useState<
    Record<string, GoogleDriveFileSummary[]>
  >({});
  const [deliveriesByConnection, setDeliveriesByConnection] = useState<
    Record<string, IntegrationDelivery[]>
  >({});
  const [loading, setLoading] = useState(true);

  const teamQuery = activeTeamId ? `?teamId=${encodeURIComponent(activeTeamId)}` : "";

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

    setLoading(true);
    const [
      slackRes,
      googleRes,
      gmailRes,
      driveRes,
      githubRes,
      telegramRes,
      sheetsRes,
      notionRes,
      feedsRes,
    ] = await Promise.all([
      fetch(`/api/integrations/slack${teamQuery}`),
      fetch(`/api/integrations/google-calendar${teamQuery}`),
      fetch(`/api/integrations/gmail${teamQuery}`),
      fetch(`/api/integrations/google-drive${teamQuery}`),
      fetch(`/api/integrations/github${teamQuery}`),
      fetch(`/api/integrations/telegram${teamQuery}`),
      fetch(`/api/integrations/google-sheets${teamQuery}`),
      fetch(`/api/integrations/notion${teamQuery}`),
      fetch(`/api/integrations/calendar-feeds${teamQuery}`),
    ]);

    const slackJson = slackRes.ok ? await slackRes.json() : { connections: [] };
    const googleJson = googleRes.ok ? await googleRes.json() : { connections: [] };
    const gmailJson = gmailRes.ok ? await gmailRes.json() : { connections: [] };
    const driveJson = driveRes.ok ? await driveRes.json() : { connections: [] };
    const githubJson = githubRes.ok ? await githubRes.json() : { connections: [] };
    const telegramJson = telegramRes.ok ? await telegramRes.json() : { connections: [] };
    const sheetsJson = sheetsRes.ok ? await sheetsRes.json() : { connections: [] };
    const notionJson = notionRes.ok ? await notionRes.json() : { connections: [] };
    const feedsJson = feedsRes.ok ? await feedsRes.json() : { feeds: [] };

    setSlackConnections(slackJson.connections || []);
    setGoogleConnections(googleJson.connections || []);
    setGmailConnections(gmailJson.connections || []);
    setDriveConnections(driveJson.connections || []);
    setGitHubConnections(githubJson.connections || []);
    setTelegramConnections(telegramJson.connections || []);
    setSheetsConnections(sheetsJson.connections || []);
    setNotionConnections(notionJson.connections || []);
    setCalendarFeeds(feedsJson.feeds || []);
    setLoading(false);
  }, [initialized, teamQuery]);

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

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

  async function createSlackConnection(input: CreateSlackConnectionInput) {
    const res = await fetch("/api/integrations/slack", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        teamId: activeTeamId,
        name: input.name,
        webhookUrl: input.webhookUrl,
        eventTypes: input.eventTypes,
      }),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Slack integration could not be created");
    }

    setSlackConnections((prev) => [json.connection, ...prev]);
    return json as { connection: IntegrationConnection };
  }

  async function updateSlackConnection(
    id: string,
    input: Partial<{ name: string; webhookUrl: string; eventTypes: WebhookEventType[]; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/slack/${id}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Slack integration could not be updated");
    }

    setSlackConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteSlackConnection(id: string) {
    const res = await fetch(`/api/integrations/slack/${id}`, {
      method: "DELETE",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Slack integration could not be deleted");
    }

    setSlackConnections((prev) => prev.filter((connection) => connection.id !== id));
    setDeliveriesByConnection((prev) => {
      const next = { ...prev };
      delete next[id];
      return next;
    });
  }

  async function fetchSlackDeliveries(connectionId: string) {
    const res = await fetch(`/api/integrations/slack/${connectionId}/deliveries?limit=20`);
    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Slack deliveries could not be loaded");
    }

    setDeliveriesByConnection((prev) => ({
      ...prev,
      [connectionId]: json.deliveries || [],
    }));
  }

  async function createCalendarFeed(input: CreateCalendarFeedInput) {
    const res = await fetch("/api/integrations/calendar-feeds", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        teamId: activeTeamId,
        name: input.name,
      }),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Calendar feed could not be created");
    }

    setCalendarFeeds((prev) => [json.feed, ...prev]);
    return json as { feed: CalendarFeedToken; feedUrl: string };
  }

  async function updateCalendarFeed(
    id: string,
    input: Partial<{ name: string; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/calendar-feeds/${id}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Calendar feed could not be updated");
    }

    setCalendarFeeds((prev) => prev.map((feed) => (feed.id === id ? json.feed : feed)));
    return json.feed as CalendarFeedToken;
  }

  async function deleteCalendarFeed(id: string) {
    const res = await fetch(`/api/integrations/calendar-feeds/${id}`, {
      method: "DELETE",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Calendar feed could not be deleted");
    }

    setCalendarFeeds((prev) => prev.filter((feed) => feed.id !== id));
  }

  async function fetchGoogleCalendars(connectionId: string) {
    const res = await fetch(`/api/integrations/google-calendar/${connectionId}/calendars`);
    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google calendars could not be loaded");
    }

    setGoogleCalendarsByConnection((prev) => ({
      ...prev,
      [connectionId]: json.calendars || [],
    }));
  }

  async function updateGoogleConnection(
    id: string,
    input: Partial<{ name: string; calendarId: string | null; calendarSummary: string | null; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/google-calendar/${id}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google Calendar connection could not be updated");
    }

    setGoogleConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function syncGoogleConnection(id: string) {
    const res = await fetch(`/api/integrations/google-calendar/${id}/sync`, {
      method: "POST",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google Calendar sync could not be started");
    }

    await fetchAll();
    return json as { synced: number; calendarId: string; calendarSummary: string | null };
  }

  async function deleteGoogleConnection(id: string) {
    const res = await fetch(`/api/integrations/google-calendar/${id}`, {
      method: "DELETE",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google Calendar connection could not be deleted");
    }

    setGoogleConnections((prev) => prev.filter((connection) => connection.id !== id));
    setGoogleCalendarsByConnection((prev) => {
      const next = { ...prev };
      delete next[id];
      return next;
    });
  }

  async function fetchGmailMessages(connectionId: string) {
    const res = await fetch(`/api/integrations/gmail/${connectionId}/messages?limit=12`);
    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Gmail messages could not be loaded");
    }

    setGmailMessagesByConnection((prev) => ({
      ...prev,
      [connectionId]: json.messages || [],
    }));
  }

  async function updateGmailConnection(
    id: string,
    input: Partial<{ name: string; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/gmail/${id}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Gmail connection could not be updated");
    }

    setGmailConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteGmailConnection(id: string) {
    const res = await fetch(`/api/integrations/gmail/${id}`, {
      method: "DELETE",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Gmail connection could not be deleted");
    }

    setGmailConnections((prev) => prev.filter((connection) => connection.id !== id));
    setGmailMessagesByConnection((prev) => {
      const next = { ...prev };
      delete next[id];
      return next;
    });
  }

  async function fetchDriveFiles(connectionId: string) {
    const res = await fetch(`/api/integrations/google-drive/${connectionId}/files?limit=12`);
    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google Drive files could not be loaded");
    }

    setDriveFilesByConnection((prev) => ({
      ...prev,
      [connectionId]: json.files || [],
    }));
  }

  async function updateDriveConnection(
    id: string,
    input: Partial<{ name: string; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/google-drive/${id}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google Drive connection could not be updated");
    }

    setDriveConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteDriveConnection(id: string) {
    const res = await fetch(`/api/integrations/google-drive/${id}`, {
      method: "DELETE",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "Google Drive connection could not be deleted");
    }

    setDriveConnections((prev) => prev.filter((connection) => connection.id !== id));
    setDriveFilesByConnection((prev) => {
      const next = { ...prev };
      delete next[id];
      return next;
    });
  }

  async function createGitHubConnection(input: CreateGitHubConnectionInput) {
    const res = await fetch("/api/integrations/github", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        teamId: activeTeamId,
        name: input.name,
        token: input.token,
      }),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "GitHub integration could not be created");
    }

    setGitHubConnections((prev) => [json.connection, ...prev]);
    return json as { connection: IntegrationConnection };
  }

  async function fetchGitHubRepos(connectionId: string) {
    const res = await fetch(`/api/integrations/github/${connectionId}/repos`);
    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "GitHub repositories could not be loaded");
    }

    setGitHubReposByConnection((prev) => ({
      ...prev,
      [connectionId]: json.repos || [],
    }));
  }

  async function updateGitHubConnection(
    id: string,
    input: Partial<{
      name: string;
      repoOwner: string | null;
      repoName: string | null;
      repoFullName: string | null;
      isActive: boolean;
    }>
  ) {
    const res = await fetch(`/api/integrations/github/${id}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(input),
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "GitHub connection could not be updated");
    }

    setGitHubConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteGitHubConnection(id: string) {
    const res = await fetch(`/api/integrations/github/${id}`, {
      method: "DELETE",
    });

    const json = await res.json();
    if (!res.ok) {
      throw new Error(json.error || "GitHub connection could not be deleted");
    }

    setGitHubConnections((prev) => prev.filter((connection) => connection.id !== id));
    setGitHubReposByConnection((prev) => {
      const next = { ...prev };
      delete next[id];
      return next;
    });
  }

  async function createTelegramConnection(input: {
    name: string;
    botToken: string;
    chatId: string;
    botUsername?: string;
    eventTypes: WebhookEventType[];
  }) {
    const res = await fetch("/api/integrations/telegram", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        teamId: activeTeamId,
        ...input,
      }),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Telegram integration could not be created");
    setTelegramConnections((prev) => [json.connection, ...prev]);
    return json as { connection: IntegrationConnection };
  }

  async function updateTelegramConnection(
    id: string,
    input: Partial<{ name: string; eventTypes: WebhookEventType[]; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/telegram/${id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(input),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Telegram integration could not be updated");
    setTelegramConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteTelegramConnection(id: string) {
    const res = await fetch(`/api/integrations/telegram/${id}`, { method: "DELETE" });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Telegram integration could not be deleted");
    setTelegramConnections((prev) => prev.filter((connection) => connection.id !== id));
  }

  async function createSheetsConnection(input: {
    name: string;
    webhookUrl: string;
    eventTypes: WebhookEventType[];
  }) {
    const res = await fetch("/api/integrations/google-sheets", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        teamId: activeTeamId,
        ...input,
      }),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Google Sheets integration could not be created");
    setSheetsConnections((prev) => [json.connection, ...prev]);
    return json as { connection: IntegrationConnection };
  }

  async function updateSheetsConnection(
    id: string,
    input: Partial<{ name: string; eventTypes: WebhookEventType[]; isActive: boolean }>
  ) {
    const res = await fetch(`/api/integrations/google-sheets/${id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(input),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Google Sheets integration could not be updated");
    setSheetsConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteSheetsConnection(id: string) {
    const res = await fetch(`/api/integrations/google-sheets/${id}`, { method: "DELETE" });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Google Sheets integration could not be deleted");
    setSheetsConnections((prev) => prev.filter((connection) => connection.id !== id));
  }

  async function createNotionConnection(input: {
    name: string;
    token: string;
    parentPageId: string;
    eventTypes: WebhookEventType[];
  }) {
    const res = await fetch("/api/integrations/notion", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        teamId: activeTeamId,
        ...input,
      }),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Notion integration could not be created");
    setNotionConnections((prev) => [json.connection, ...prev]);
    return json as { connection: IntegrationConnection };
  }

  async function updateNotionConnection(
    id: string,
    input: Partial<{
      name: string;
      parentPageId: string | null;
      eventTypes: WebhookEventType[];
      isActive: boolean;
    }>
  ) {
    const res = await fetch(`/api/integrations/notion/${id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(input),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Notion integration could not be updated");
    setNotionConnections((prev) =>
      prev.map((connection) => (connection.id === id ? json.connection : connection))
    );
    return json.connection as IntegrationConnection;
  }

  async function deleteNotionConnection(id: string) {
    const res = await fetch(`/api/integrations/notion/${id}`, { method: "DELETE" });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error || "Notion integration could not be deleted");
    setNotionConnections((prev) => prev.filter((connection) => connection.id !== id));
  }

  return {
    activeTeamId,
    slackConnections,
    googleConnections,
    gmailConnections,
    driveConnections,
    githubConnections,
    telegramConnections,
    sheetsConnections,
    notionConnections,
    calendarFeeds,
    googleCalendarsByConnection,
    githubReposByConnection,
    gmailMessagesByConnection,
    driveFilesByConnection,
    deliveriesByConnection,
    loading,
    createSlackConnection,
    updateSlackConnection,
    deleteSlackConnection,
    fetchSlackDeliveries,
    fetchGoogleCalendars,
    updateGoogleConnection,
    syncGoogleConnection,
    deleteGoogleConnection,
    fetchGmailMessages,
    updateGmailConnection,
    deleteGmailConnection,
    fetchDriveFiles,
    updateDriveConnection,
    deleteDriveConnection,
    createGitHubConnection,
    fetchGitHubRepos,
    updateGitHubConnection,
    deleteGitHubConnection,
    createTelegramConnection,
    updateTelegramConnection,
    deleteTelegramConnection,
    createSheetsConnection,
    updateSheetsConnection,
    deleteSheetsConnection,
    createNotionConnection,
    updateNotionConnection,
    deleteNotionConnection,
    createCalendarFeed,
    updateCalendarFeed,
    deleteCalendarFeed,
    refetch: fetchAll,
  };
}
