import { useCallback, useEffect, useRef, useState } from 'react';
import { ApiError, request } from './client';
import type { components } from './generated/v1';

export type DashboardChannel = components['schemas']['ChannelResponseModel'];
export type DashboardChannelState = components['schemas']['ChannelStateResponseModel'];
export type DashboardHealthCheck = components['schemas']['HealthCheckResponseModel'];
type DashboardMediaSource = components['schemas']['MediaSourceResponseModel'];
type DashboardPlayouts = components['schemas']['PagedPlayoutsResponseModel'];
export type DashboardVersion = components['schemas']['CombinedVersion'];

export interface DashboardData {
  channels: DashboardChannel[];
  channelStates: DashboardChannelState[];
  mediaSources: DashboardMediaSource[];
  playouts: DashboardPlayouts;
}

export type DashboardQueryState =
  | { data: DashboardData; error: null; status: 'success' }
  | { data: null; error: string; status: 'error' }
  | { data: null; error: null; status: 'loading' };

export type DashboardHealthQueryState =
  | { checks: DashboardHealthCheck[]; error: null; refresh: () => void; status: 'success' }
  | { checks: null; error: string; refresh: () => void; status: 'error' }
  | { checks: null; error: null; refresh: () => void; status: 'loading' };

export type DashboardVersionQueryState =
  | { error: null; status: 'success'; version: DashboardVersion }
  | { error: string; status: 'error'; version: null }
  | { error: null; status: 'loading'; version: null };

type DashboardHealthState =
  | { checks: DashboardHealthCheck[]; error: null; status: 'success' }
  | { checks: null; error: string; status: 'error' }
  | { checks: null; error: null; status: 'loading' };

export async function getDashboardData(): Promise<DashboardData> {
  const [channels, channelStates, mediaSources, playouts] = await Promise.all([
    request<DashboardChannel[]>('/api/v1/channels'),
    request<DashboardChannelState[]>('/api/v1/channels/state'),
    request<DashboardMediaSource[]>('/api/v1/media-sources'),
    request<DashboardPlayouts>('/api/v1/playouts')
  ]);

  return { channels, channelStates, mediaSources, playouts };
}

export function getDashboardHealth(refresh = false): Promise<DashboardHealthCheck[]> {
  // Health results are cached server-side; the on-demand "Refresh health" action forces a fresh run.
  return request<DashboardHealthCheck[]>(refresh ? '/api/v1/health?refresh=true' : '/api/v1/health');
}

export function getDashboardVersion(): Promise<DashboardVersion> {
  return request<DashboardVersion>('/api/v1/version');
}

export function useDashboardQuery(): DashboardQueryState {
  const [state, setState] = useState<DashboardQueryState>({
    data: null,
    error: null,
    status: 'loading'
  });

  useEffect(() => {
    let active = true;

    getDashboardData()
      .then((data) => {
        if (active) {
          setState({ data, error: null, status: 'success' });
        }
      })
      .catch((error: unknown) => {
        if (active) {
          setState({ data: null, error: messageFromError(error), status: 'error' });
        }
      });

    return () => {
      active = false;
    };
  }, []);

  return state;
}

export function useDashboardHealthQuery(): DashboardHealthQueryState {
  const [state, setState] = useState<DashboardHealthState>({
    checks: null,
    error: null,
    status: 'loading'
  });

  const activeRef = useRef(true);

  useEffect(() => {
    activeRef.current = true;

    return () => {
      activeRef.current = false;
    };
  }, []);

  const loadHealth = useCallback((refresh: boolean) => {
    getDashboardHealth(refresh)
      .then((checks) => {
        if (activeRef.current) {
          setState({ checks, error: null, status: 'success' });
        }
      })
      .catch((error: unknown) => {
        if (activeRef.current) {
          setState({ checks: null, error: messageFromError(error), status: 'error' });
        }
      });
  }, []);

  const refresh = useCallback(() => {
    setState({ checks: null, error: null, status: 'loading' });
    loadHealth(true);
  }, [loadHealth]);

  useEffect(() => {
    loadHealth(false);
  }, [loadHealth]);

  if (state.status === 'success') {
    return { checks: state.checks, error: null, refresh, status: 'success' };
  }

  if (state.status === 'error') {
    return { checks: null, error: state.error, refresh, status: 'error' };
  }

  return { checks: null, error: null, refresh, status: 'loading' };
}

export function useDashboardVersionQuery(): DashboardVersionQueryState {
  const [state, setState] = useState<DashboardVersionQueryState>({
    error: null,
    status: 'loading',
    version: null
  });

  useEffect(() => {
    let active = true;

    getDashboardVersion()
      .then((version) => {
        if (active) {
          setState({ error: null, status: 'success', version });
        }
      })
      .catch((error: unknown) => {
        if (active) {
          setState({ error: messageFromError(error), status: 'error', version: null });
        }
      });

    return () => {
      active = false;
    };
  }, []);

  return state;
}

function messageFromError(error: unknown): string {
  if (error instanceof ApiError) {
    return error.detail ?? error.message;
  }

  if (error instanceof Error) {
    return error.message;
  }

  return 'Unable to load dashboard';
}
