"use server";

import { createClient } from "../lib/supabase/server";
import { revalidatePath } from "next/cache";
import { OAuth2Client } from "google-auth-library";
import { PingResult } from "@/types";
import z from "zod";
import { cache } from "react";

export const rpcUpdatePlan = async (
  client_id: number,
  strategy_id?: number | null,
) => {
  const supabase = await createClient();

  if (strategy_id) {
    const { error } = await supabase.rpc(
      "plan_12m_from_subscription_starting_today",
      {
        p_client_id: client_id,
        p_strategy_id: strategy_id,
      },
    );
    if (error) return { status: 500, message: error.message };

    const { error: strategy_error } = await supabase
      .from("strategy")
      .update({ strategy_status: "approved" })
      .eq("client_id", client_id)
      .eq("id", strategy_id);

    if (strategy_error) return { status: 500, message: strategy_error.message };
  } else {
    const { error } = await supabase.rpc(
      "plan_12m_from_subscription_starting_today",
      {
        p_client_id: client_id,
      },
    );

    if (error) return { status: 500, message: error.message };
  }

  const { data: existingApproval } = await supabase
    .from("Approval")
    .select("client_id")
    .eq("client_id", client_id)
    .maybeSingle();

  let approvalError;

  if (existingApproval) {
    const { error } = await supabase
      .from("Approval")
      .update({ approved: true })
      .eq("client_id", client_id);
    approvalError = error;
  } else {
    const { error } = await supabase
      .from("Approval")
      .insert({ client_id: client_id, approved: true });
    approvalError = error;
  }

  if (approvalError) return { status: 500, message: approvalError.message };

  return { status: 200, message: "Plan Approved" };
};

export const removeUrl = async (url_id: number, client_id: number) => {
  const supabase = await createClient();

  const { error } = await supabase
    .from("URL")
    .update({ include: false, month: null })
    .eq("url_id", url_id)
    .eq("client_id", client_id);

  if (error) {
    return { status: 500, message: error.message };
  } else {
    revalidatePath("/", "layout");
    return { status: 200, message: "Item removed!" };
  }
};

export const removeUrlContent = async (url_id: number, client_id: number) => {
  const supabase = await createClient();

  const { data: schedule, error: fetchError } = await supabase
    .from("content_schedule")
    .select("id, url_id, plan_month, client_id")
    .eq("client_id", client_id)
    .order("plan_month", { ascending: true })
    .order("id", { ascending: true });

  if (fetchError || !schedule) {
    return {
      status: 500,
      message: fetchError?.message || "Failed to fetch schedule",
    };
  }

  const deleteIndex = schedule.findIndex((item) => item.url_id === url_id);
  if (deleteIndex === -1) {
    return { status: 404, message: "Item not found in schedule" };
  }

  const deletedItem = schedule[deleteIndex];

  const { error: deleteError } = await supabase
    .from("content_schedule")
    .delete()
    .eq("url_id", url_id)
    .eq("client_id", client_id);

  if (deleteError) {
    return { status: 500, message: deleteError.message };
  }

  const updates: { id: number; plan_month: number }[] = [];
  let currentMonth = deletedItem.plan_month;

  while (true) {
    const nextMonth = currentMonth + 1;
    const itemsInNextMonth = schedule.filter(
      (item) => item.url_id !== url_id && item.plan_month === nextMonth,
    );

    if (itemsInNextMonth.length === 0) {
      break;
    }

    const itemToShift = itemsInNextMonth[0];
    updates.push({
      id: itemToShift.id,
      plan_month: currentMonth,
    });

    currentMonth = nextMonth;
  }

  if (updates.length > 0) {
    const updatePromises = updates.map((update) =>
      supabase
        .from("content_schedule")
        .update({ plan_month: update.plan_month })
        .eq("id", update.id),
    );

    const results = await Promise.all(updatePromises);
    const hasError = results.some((result) => result.error);

    if (hasError) {
      console.error("Shift error during updates");
      return { status: 500, message: "Error shifting schedule" };
    }
  }

  revalidatePath("/", "layout");
  return { status: 200, message: "Item removed and schedule shifted!" };
};

const FormSchema = z.object({
  feedback: z.string().min(1, {
    message: "Message can't be empty.",
  }),
  type: z.enum(["bug", "general"]),
  image_url: z.string().optional(),
});

export const addFeedback = async (
  data: z.infer<typeof FormSchema>,
  client_id: string | number | undefined,
) => {
  const supabase = await createClient();
  const result = FormSchema.safeParse(data);

  if (!result.success) {
    return { status: 500, error: "Invalid form data" };
  }

  const { error } = await supabase.from("feedback").insert({
    client_id: client_id,
    feedback: result.data.feedback,
    type: result.data.type,
    image_url: result.data.image_url,
  });

  if (error) {
    return { status: 500, message: error.message };
  }

  return { status: 200, message: "Message send!" };
};
// ===========AUTH
export async function signIn(formData: { email: string; password: string }) {
  const supabase = await createClient();
  const { email, password } = formData;

  const { error } = await supabase.auth.signInWithPassword({
    email,
    password,
  });

  if (error) {
    console.error("Sign in error:", error.message);
    return { status: 401, message: error.message };
  }

  // revalidatePath("/", "layout");
  return { status: 200, message: "Successfully signed" };
}

export async function signOut() {
  const supabase = await createClient();
  await supabase.auth.signOut();

  revalidatePath("/", "layout");
  return { status: 200, message: "Successfully signed out" };
}
// ===========AUTH
function getOauthClient() {
  return new OAuth2Client(
    process.env.GOOGLE_CLIENT_ID,
    process.env.GOOGLE_CLIENT_SECRET,
    process.env.GOOGLE_REDIRECT_URI,
  );
}
export const getSearchConsoleDataForSite = cache(
  async (
    siteUrl: string,
    siteDomain: string,
    dimension: boolean,
    startDate: string,
    endDate: string,
  ) => {
    const refreshToken = process.env.GOOGLE_REFRESH_TOKEN;

    if (!refreshToken) {
      throw new Error(
        "Not authenticated. Please authorize the application first.",
      );
    }

    const oauth2Client = getOauthClient();
    oauth2Client.setCredentials({
      refresh_token: refreshToken,
    });

    const accessToken = await oauth2Client.getAccessToken();

    const apiUrl = `https://searchconsole.googleapis.com/webmasters/v3/sites/${encodeURIComponent(
      siteDomain,
    )}/searchAnalytics/query`;

    const requestBody = dimension
      ? {
          startDate,
          endDate,
          dimensions: ["DATE"],
          dimensionFilterGroups: [
            {
              filters: [
                {
                  dimension: "PAGE",
                  operator: "EQUALS",
                  expression: siteUrl,
                },
              ],
            },
          ],
          rowLimit: 100,
        }
      : {
          startDate,
          endDate,
          dimensionFilterGroups: [
            {
              filters: [
                {
                  dimension: "PAGE",
                  operator: "EQUALS",
                  expression: siteUrl,
                },
              ],
            },
          ],
        };

    try {
      const response = await fetch(apiUrl, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${accessToken.token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(requestBody),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.error.message);
      }

      const data = await response.json();

      return data;
    } catch (error: any) {
      console.error("API Error:", error.message);
      return { error: "InSpace does not have premissions for this site." };
    }
  },
);

export const checkUrlExists = cache(
  async (url: string): Promise<PingResult> => {
    if (!url.startsWith("http://") && !url.startsWith("https://")) {
      return {
        exists: false,
        message: "URL must start with http:// or https://",
      };
    }

    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000);

      const response = await fetch(url, {
        method: "HEAD",
        signal: controller.signal,
        cache: "no-store",
        headers: { "User-Agent": "NextJS-Health-Check" },
      });

      clearTimeout(timeoutId);

      return {
        exists: true,
        status: response.status,
        message: response.ok
          ? "Site is Online"
          : `Site reachable but returned ${response.status}`,
      };
    } catch (error: any) {
      if (error.name === "AbortError") {
        return {
          exists: false,
          message: "Request timed out (site might be down)",
        };
      }

      return {
        exists: false,
        message: "Could not connect to host (DNS or Network Error)",
      };
    }
  },
);
