import { DeploymentEvent, DeploymentFormValues, Repository } from '@/types/deployment';
import useSWR from 'swr';
import { fetcher } from '../hooks/fetcher';
import { ApiResponse } from '@/src/types/api';
import { GetProjectsProjects } from '@vercel/sdk/models/getprojectsop.js';
import { GetDeploymentResponseBody } from '@vercel/sdk/models/getdeploymentop.js';

interface PollEventsOptions {
  maxRetries?: number;
  interval?: number;
  onUpdate?: (events: DeploymentEvent[]) => void;
  emptyEventsThreshold?: number;
}

export class VercelService {
  static async createProject(project: Partial<DeploymentFormValues>) {
    return await fetch('/api/vercel/projects', {
      method: 'POST',
      body: JSON.stringify(project),
    });
  }

  static async createDeployment(project: DeploymentFormValues) {
    return await fetch('/api/vercel/deployments', {
      method: 'POST',
      body: JSON.stringify(project),
    });
  }

  static async getDeploymentEvents(id: string) {
    const response = await fetch(`/api/vercel/deployments/${id}/events`);
    const data = await response.json();
    return data.data;
  }

  static async getDeployment(id: string) {
    const response = await fetch(`/api/vercel/deployments/${id}`);
    return response.json();
  }

  static async pollDeploymentEvents(
    id: string,
    { interval = 5000, onUpdate, emptyEventsThreshold = 2 }: PollEventsOptions = {}
  ) {
    let sameEventsLengthCount = 0;
    let previousEventsLength = 0;

    const poll = async (): Promise<DeploymentEvent[]> => {
      const events = await this.getDeploymentEvents(id);

      if (onUpdate) {
        onUpdate(events);
      }

      if (events.length === previousEventsLength) {
        sameEventsLengthCount++;
        if (sameEventsLengthCount >= emptyEventsThreshold) {
          const deployment = await this.getDeployment(id);
          if (
            deployment.data.readyState === 'READY' ||
            deployment.data.readyState === 'ERROR' ||
            deployment.data.readyState === 'CANCELLED'
          ) {
            const finalEvents = [
              ...events,
              {
                date: new Date().getTime(),
                id: crypto.randomUUID(),
                text: `Deployment finished with status ${deployment.data.readyState}`,
                type: 'stdout',
              },
            ];
            if (onUpdate) {
              onUpdate(finalEvents);
            }
            return finalEvents;
          }
        }
      } else {
        sameEventsLengthCount = 0;
        previousEventsLength = events.length;
      }

      await new Promise((resolve) => setTimeout(resolve, interval));
      return poll();
    };

    return poll();
  }

  static async updateProject(id: string, project: Partial<DeploymentFormValues>) {
    return await fetch(`/api/vercel/projects/${id}`, {
      method: 'PUT',
      body: JSON.stringify(project),
    });
  }

  static async deleteProject(id: string) {
    return await fetch(`/api/vercel/projects/${id}`, {
      method: 'DELETE',
    });
  }
}

export const useVercelProjects = (search = '', authToken?: string) => {
  const { data, error, isLoading, mutate } = useSWR<ApiResponse<GetProjectsProjects[]>>(
    authToken ? `/api/vercel/projects?search=${search}` : null,
    fetcher
  );
  return { projects: data?.data ?? [], isLoading, error, mutate };
};

export const useVercelProject = (id: string, authToken?: string) => {
  const { data, error, isLoading, mutate } = useSWR<ApiResponse<GetProjectsProjects>>(
    authToken ? `/api/vercel/projects/${id}` : null,
    fetcher
  );
  return { project: data?.data ?? null, isLoading, error, mutate };
};

export const useVercelDeployments = () => {
  const { data, error, isLoading, mutate } = useSWR<ApiResponse<GetDeploymentResponseBody[]>>(
    '/api/vercel/deployments',
    fetcher
  );
  return { deployments: data?.data ?? [], isLoading, error, mutate };
};

export const useVercelDeployment = (id: string) => {
  const { data, error, isLoading, mutate } = useSWR<ApiResponse<GetDeploymentResponseBody>>(
    `/api/vercel/deployments/${id}`,
    fetcher
  );
  return { deployment: data?.data ?? null, isLoading, error, mutate };
};

export const useVercelRepositories = (search: string) => {
  const { data, error, isLoading, mutate } = useSWR<ApiResponse<Repository[]>>(
    `/api/vercel/integrations/repos?search=${search}`,
    fetcher
  );
  return { repositories: data?.data ?? [], isLoading, error, mutate };
};
