import { useState, useEffect, useMemo } from 'react';
import axios from 'B/axios';

export type DashType = 'iframe' | 'news' | 'dash' | 'dashboard' | 'map';

interface BaseDash {
  dashID: number | '';
  refreshMinutes: number;
  count: number;
  chart_start: number;
  chart_entities: number;
  dashboardID: number;
  type: DashType;
}

export type NewDash = BaseDash;
export interface Dash extends BaseDash {
  id: number;
}
export interface BaseDashboard {
  contentID: number;
  name: string;
  type: string;
}
export type NewDashboard = BaseDashboard;

export type OnChangeProps = 'dashID' | 'refreshMinutes' | 'count';

type UpdateDash = {
  id: number;
  refreshTime: number;
  contentID: number;
  count: number;
  dashboardID: number;
  type: DashType;
};

type CreateDash = {
  refreshTime: number;
  contentID: number;
  count: number;
  dashboardID: number;
  type: DashType;
};
type CreateDashboard = {
  name: string;
  type: string;
};

async function updateDash(updateObj: UpdateDash) {
  return await axios.post(`/dashboards/${updateObj.id}`, {
    contentID: updateObj.contentID,
    refreshTime: updateObj.refreshTime,
    contentCount: updateObj.count,
    dashboardID: updateObj.dashboardID,
    type: updateObj.type,
  });
}

async function createDash(createObj: CreateDash) {
  return axios.post('/dashboards', {
    contentID: createObj.contentID,
    refreshTime: createObj.refreshTime,
    contentCount: createObj.count,
    type: createObj.type,
    dashboardID: createObj.dashboardID,
  });
}

export const useUpdateDashboard = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const updateDashboard = async (updateObj: { id: number; name: string }) => {
    setIsLoading(true);
    try {
      await axios.post(`/dashboard/${updateObj.id}`, {
        name: updateObj.name,
      });
    } catch (error) {
      setError(error);
    } finally {
      setIsLoading(false);
      window.location.reload();
    }
  };

  return { updateDashboard, isLoading, error };
};

export const useCreateDashboard = () => {
  const [isOpen, setIsOpen] = useState(false);

  const openDialog = () => setIsOpen(true);
  const closeDialog = () => setIsOpen(false);

  const createDashboard = async (dashboardName: string) => {
    try {
      const response = await axios.post('/dashboard', {
        name: dashboardName,
      });
      const newDashboardId = response.data.id;
      closeDialog();
      return newDashboardId;
    } catch (error) {
      console.error('Fehler beim Erstellen des Dashboards:', error);
      closeDialog();
    }
  };

  return { isOpen, openDialog, closeDialog, createDashboard };
};

// Reihenfolge vom Server abrufen
export const useFetchDashboardOrder = () => {
  const fetchOrder = async (): Promise<number[]> => {
    const response = await axios.get('/dashboard/order');
    return response.data.order;
  };

  return { fetchOrder };
};

// Reihenfolge auf dem Server speichern
export const useReorderDashboards = () => {
  const reorderDashboards = async (orderedIds: number[]): Promise<void> => {
    const query = new URLSearchParams({ order: orderedIds.join(',') }).toString();
    await axios.get(`/dashboard/order/save?${query}`);
  };

  return { reorderDashboards };
};

export const useDeleteDashboard = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const deleteDashboard = async (id: number) => {
    setIsLoading(true);
    try {
      await axios.delete(`/dashboard/${id}`);
    } catch (error) {
      setError(error);
      throw error;
    } finally {
      setIsLoading(false);
    }
  };

  return { deleteDashboard, isLoading, error };
};

export const useUpdateDash = (d: Dash) => {
  const [dash, setDash] = useState<Dash>(d);

  const onChange = (name: OnChangeProps) => (e) => {
    (dash[name] as any) = Number(e.target.value);
    setDash({ ...dash });
  };

  const update = () => {
    if (dash.dashID === '') return;

    updateDash({
      contentID: dash.dashID,
      count: dash.count,
      id: dash.id,
      refreshTime: dash.refreshMinutes,
      dashboardID: dash.dashboardID,
      type: dash.type,
    }).then(() => {
      location.reload();
    });
  };

  const onChangeDash = (e) => {
    const chosenDash = e.target.value.split('::');
    if (chosenDash.length !== 2) return;
    const type: DashType = chosenDash[0];
    const dashID = Number(chosenDash[1]);
    setDash({ ...dash, type, dashID });
  };

  return [
    { dashboard: dash },
    { onChange, update, onChangeDash },
  ];
};

export const useCreateDash = (dashboardId) => {
  const baseDash = useMemo<NewDash>(() => ({
    dashID: '',
    refreshMinutes: 30,
    count: 100,
    dashboardID: dashboardId,
    type: 'dash',
  }), [dashboardId]);

  const [dash, setDash] = useState<NewDash>(baseDash);
  const [isOpen, setIsOpen] = useState(false);

  useEffect(() => {
    if (!isOpen) setDash(baseDash);
  }, [baseDash, isOpen]);

  const openDialog = () => setIsOpen(true);
  const closeDialog = () => {
    setDash(baseDash);
    setIsOpen(false);
  };

  const onChangeDash = (e) => {
    const chosenDash = e.target.value.split('::');
    if (chosenDash.length !== 2) return;
    const type: DashType = chosenDash[0];
    const dashID = Number(chosenDash[1]);
    setDash({ ...dash, type, dashID });
  };

  const onChange = (name: OnChangeProps) => (e) => {
    if (e.target.value === 'tasko-news') {
      (dash[name] as any) = e.target.value;
      setDash({ ...dash });
      return;
    }
    (dash[name] as any) = Number(e.target.value);
    setDash({ ...dash });
  };

  const create = async () => {
    await createDash({
      contentID: dash.dashID as number,
      count: dash.count,
      refreshTime: dash.refreshMinutes,
      dashboardID: dash.dashboardID,
      type: dash.type,
    });
    location.reload();
  };

  return [
    { dashboard: dash, isOpen },
    { openDialog, closeDialog, onChange, create, createDash, onChangeDash },
  ];
};

// ---- Sharing Hooks ----
export const useShareDashboard = () => {
  const shareDashboard = async ({
    dashboardId,
    shared,
  }: {
    dashboardId: number;
    shared: boolean;
  }): Promise<{ id: number; is_public: boolean } | null> => {
    const res = await axios.post(`/dashboard/${dashboardId}/share`, { shared });

    // Falls 204/empty body kommt, res.data ist evtl. undefined
    const data = res?.data;
    if (data && typeof data.is_public === 'boolean') {
      return { id: data.id ?? dashboardId, is_public: data.is_public };
    }

    // Fallback: wenn der Server nichts zurückgibt, nehmen wir den angeforderten Wert an
    return { id: dashboardId, is_public: !!shared };
  };

  return { shareDashboard } as const;
};


// ---- Folder Hooks ----

export type DashboardFolder = {
  id: number;
  name: string;
};

export const useFolders = () => {
  const fetchFolders = async (): Promise<DashboardFolder[]> => {
    const res = await axios.get<{ folders: DashboardFolder[] }>('/dashboard/folders');
    return res.data?.folders ?? [];
  };

  const createFolder = async (name: string): Promise<number | null> => {
    const res = await axios.post<{ id: number; name: string }>('/dashboard/folder', { name });
    return res.data?.id ?? null;
  };

  const updateFolder = async (id: number, name: string): Promise<void> => {
    await axios.post(`/dashboard/folder/${id}`, { name });
  };

  const deleteFolder = async (id: number): Promise<void> => {
    await axios.delete(`/dashboard/folder/${id}`);
  };

  const moveDashboardToFolder = async (
    dashboardId: number,
    folderId: number | null
  ): Promise<void> => {
    await axios.post(`/dashboard/${dashboardId}/move-to-folder`, {
      folder_id: folderId,
    });
  };

  return { fetchFolders, createFolder, updateFolder, deleteFolder, moveDashboardToFolder };
};

// ---- Order V2 (mixed format with folders) ----

export type OrderItem = number | { folder_id: number; dashboards: number[] };

export const useSaveOrderV2 = () => {
  const saveOrderV2 = async (order: OrderItem[]): Promise<void> => {
    await axios.post('/dashboard/order/save', { order });
  };

  return { saveOrderV2 };
};

export interface SearchUser { id: string; name: string; email?: string }
export interface SearchGroup { id: string; name: string }

export const useFetchUsers = () => {
  const searchUsers = async (q: string): Promise<SearchUser[]> => {
    const res = await axios.get('/user/search', { params: { q } });
    const raw = (res.data && (res.data.users ?? res.data)) || [];
    return (raw as any[]).map((u) => ({ id: String(u.id ?? u.userId ?? u.uuid), name: u.name ?? u.displayName ?? '', email: u.email ?? '' }));
  };
  return { searchUsers } as const;
};

export const useFetchGroups = () => {
  const [allGroups, setAllGroups] = useState<SearchGroup[]>([]);
  const [loaded, setLoaded] = useState(false);
  const [error, setError] = useState<any>(null);

  useEffect(() => {
    let mounted = true;
    (async () => {
      try {
        const res = await axios.get('/user/getGroups');
        const raw: any[] = Array.isArray(res.data) ? res.data : [];
        const mapped: SearchGroup[] = raw.map((g) => ({ id: String(g.usg_id), name: g.usg_name }));
        if (mounted) {
          setAllGroups(mapped);
          setLoaded(true);
        }
      } catch (e) {
        if (mounted) setError(e);
      }
    })();
    return () => { mounted = false; };
  }, []);

  const searchGroups = async (q: string): Promise<SearchGroup[]> => {
    if (!loaded) return [];
    const query = (q || '').trim().toLowerCase();
    if (!query) return allGroups;
    const starts = allGroups.filter((g) => g.name.toLowerCase().startsWith(query));
    const rest = allGroups.filter((g) => !g.name.toLowerCase().startsWith(query) && g.name.toLowerCase().includes(query));
    return [...starts, ...rest];
  };

  return { searchGroups, error } as const;
};

export const useHasSharePermission = (feature: string) => {
  const [allowed, setAllowed] = useState<boolean>(false);
  useEffect(() => {
    (async () => {
      try {
        const res = await axios.get('/me/permissions', { params: { feature } });
        setAllowed(!!res.data.allowed);
      } catch {
        setAllowed(false);
      }
    })();
  }, [feature]);
  return { hasSharePermission: allowed };
};
