import { useState, useEffect, useCallback } from 'react';
import axios from 'axios';
import {
  Permission,
  SystemRole,
  Team,
  SystemUser,
  PermissionFilters,
  RoleFilters,
  TeamFilters,
  PermissionFormData,
  RoleFormData,
  TeamFormData,
  TeamMemberFormData,
  UpdateTeamMemberRequest,
  PermissionModule,
  ZeiterfassungRoleLink,
} from '../types/permissions';

const API_BASE = '/api';

// ============================================================
// Permissions Hook
// ============================================================
interface UsePermissionsReturn {
  permissions: Permission[];
  loading: boolean;
  error: string | null;
  modules: PermissionModule[];
  categories: string[];
  refresh: (filters?: PermissionFilters) => Promise<void>;
  create: (data: PermissionFormData) => Promise<Permission>;
  update: (id: number, data: Partial<PermissionFormData>) => Promise<Permission>;
  remove: (id: number) => Promise<void>;
  getById: (id: number) => Promise<Permission>;
}

export function usePermissions(): UsePermissionsReturn {
  const [permissions, setPermissions] = useState<Permission[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [modules, setModules] = useState<PermissionModule[]>([]);
  const [categories, setCategories] = useState<string[]>([]);

  const refresh = useCallback(async (filters?: PermissionFilters) => {
    try {
      setLoading(true);
      setError(null);
      const params: Record<string, any> = {};
      if (filters?.module) params.module = filters.module;
      if (filters?.category) params.category = filters.category;
      if (filters?.active !== undefined) params.active = filters.active;
      if (filters?.search) params.search = filters.search;

      const response = await axios.get(`${API_BASE}/permissions`, { params });
      setPermissions(response.data.data || response.data);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load permissions');
      console.error('Error fetching permissions:', err);
    } finally {
      setLoading(false);
    }
  }, []);

  const fetchModulesAndCategories = useCallback(async () => {
    try {
      const [modulesRes, categoriesRes] = await Promise.all([
        axios.get(`${API_BASE}/permissions/modules`),
        axios.get(`${API_BASE}/permissions/categories`),
      ]);
      setModules(modulesRes.data.data || modulesRes.data);
      setCategories(categoriesRes.data.data || categoriesRes.data);
    } catch (err: any) {
      console.error('Error fetching modules/categories:', err);
    }
  }, []);

  const create = useCallback(async (data: PermissionFormData): Promise<Permission> => {
    const response = await axios.post(`${API_BASE}/permissions`, data);
    await refresh();
    return response.data;
  }, [refresh]);

  const update = useCallback(async (id: number, data: Partial<PermissionFormData>): Promise<Permission> => {
    const response = await axios.put(`${API_BASE}/permissions/${id}`, data);
    await refresh();
    return response.data;
  }, [refresh]);

  const remove = useCallback(async (id: number): Promise<void> => {
    await axios.delete(`${API_BASE}/permissions/${id}`);
    await refresh();
  }, [refresh]);

  const getById = useCallback(async (id: number): Promise<Permission> => {
    const response = await axios.get(`${API_BASE}/permissions/${id}`);
    return response.data;
  }, []);

  useEffect(() => {
    refresh();
    fetchModulesAndCategories();
  }, []);

  return {
    permissions,
    loading,
    error,
    modules,
    categories,
    refresh,
    create,
    update,
    remove,
    getById,
  };
}

// ============================================================
// Roles Hook
// ============================================================
interface UseRolesReturn {
  roles: SystemRole[];
  loading: boolean;
  error: string | null;
  refresh: (filters?: RoleFilters) => Promise<void>;
  create: (data: RoleFormData) => Promise<SystemRole>;
  update: (id: number, data: Partial<RoleFormData>) => Promise<SystemRole>;
  remove: (id: number) => Promise<void>;
  getById: (id: number) => Promise<SystemRole>;
  syncPermissions: (roleId: number, permissionIds: number[]) => Promise<void>;
  getUsers: (roleId: number) => Promise<SystemUser[]>;
  assignUser: (roleId: number, userId: number) => Promise<void>;
  removeUser: (roleId: number, userId: number) => Promise<void>;
  getZeiterfassungRoles: (roleId: number) => Promise<ZeiterfassungRoleLink[]>;
  linkZeiterfassungRole: (roleId: number, zrId: number, active?: boolean) => Promise<void>;
  unlinkZeiterfassungRole: (roleId: number, zrId: number) => Promise<void>;
}

export function useRoles(): UseRolesReturn {
  const [roles, setRoles] = useState<SystemRole[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const refresh = useCallback(async (filters?: RoleFilters) => {
    try {
      setLoading(true);
      setError(null);
      const params: Record<string, any> = {};
      if (filters?.active !== undefined) params.active = filters.active;
      if (filters?.with_permissions) params.with_permissions = true;
      if (filters?.with_users) params.with_users = true;
      if (filters?.search) params.search = filters.search;

      const response = await axios.get(`${API_BASE}/roles`, { params });
      setRoles(response.data.data || response.data);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load roles');
      console.error('Error fetching roles:', err);
    } finally {
      setLoading(false);
    }
  }, []);

  const create = useCallback(async (data: RoleFormData): Promise<SystemRole> => {
    const response = await axios.post(`${API_BASE}/roles`, data);
    await refresh();
    return response.data;
  }, [refresh]);

  const update = useCallback(async (id: number, data: Partial<RoleFormData>): Promise<SystemRole> => {
    const response = await axios.put(`${API_BASE}/roles/${id}`, data);
    await refresh();
    return response.data;
  }, [refresh]);

  const remove = useCallback(async (id: number): Promise<void> => {
    await axios.delete(`${API_BASE}/roles/${id}`);
    await refresh();
  }, [refresh]);

  const getById = useCallback(async (id: number): Promise<SystemRole> => {
    const response = await axios.get(`${API_BASE}/roles/${id}`);
    return response.data;
  }, []);

  const syncPermissions = useCallback(async (roleId: number, permissionIds: number[]): Promise<void> => {
    await axios.post(`${API_BASE}/roles/${roleId}/permissions`, { permission_ids: permissionIds });
    await refresh({ with_permissions: true });
  }, [refresh]);

  const getUsers = useCallback(async (roleId: number): Promise<SystemUser[]> => {
    const response = await axios.get(`${API_BASE}/roles/${roleId}/users`);
    return response.data.data || response.data;
  }, []);

  const assignUser = useCallback(async (roleId: number, userId: number): Promise<void> => {
    await axios.post(`${API_BASE}/roles/${roleId}/users`, { user_id: userId });
  }, []);

  const removeUser = useCallback(async (roleId: number, userId: number): Promise<void> => {
    await axios.delete(`${API_BASE}/roles/${roleId}/users/${userId}`);
  }, []);

  const getZeiterfassungRoles = useCallback(async (roleId: number): Promise<ZeiterfassungRoleLink[]> => {
    const response = await axios.get(`${API_BASE}/roles/${roleId}/zeiterfassung-roles`);
    return response.data.data || response.data;
  }, []);

  const linkZeiterfassungRole = useCallback(async (roleId: number, zrId: number, active = true): Promise<void> => {
    await axios.post(`${API_BASE}/roles/${roleId}/zeiterfassung-roles`, {
      zeiterfassung_role_id: zrId,
      active,
    });
  }, []);

  const unlinkZeiterfassungRole = useCallback(async (roleId: number, zrId: number): Promise<void> => {
    await axios.delete(`${API_BASE}/roles/${roleId}/zeiterfassung-roles/${zrId}`);
  }, []);

  useEffect(() => {
    refresh({ with_permissions: true });
  }, []);

  return {
    roles,
    loading,
    error,
    refresh,
    create,
    update,
    remove,
    getById,
    syncPermissions,
    getUsers,
    assignUser,
    removeUser,
    getZeiterfassungRoles,
    linkZeiterfassungRole,
    unlinkZeiterfassungRole,
  };
}

// ============================================================
// Teams Hook
// ============================================================
interface UseTeamsReturn {
  teams: Team[];
  loading: boolean;
  error: string | null;
  refresh: (filters?: TeamFilters) => Promise<void>;
  create: (data: TeamFormData) => Promise<Team>;
  update: (id: number, data: Partial<TeamFormData>) => Promise<Team>;
  remove: (id: number) => Promise<void>;
  getById: (id: number) => Promise<Team>;
  getMembers: (teamId: number) => Promise<SystemUser[]>;
  addMember: (teamId: number, data: TeamMemberFormData) => Promise<void>;
  updateMember: (teamId: number, userId: number, data: UpdateTeamMemberRequest) => Promise<void>;
  removeMember: (teamId: number, userId: number) => Promise<void>;
  syncRoles: (teamId: number, roleIds: number[]) => Promise<void>;
}

export function useTeams(): UseTeamsReturn {
  const [teams, setTeams] = useState<Team[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const refresh = useCallback(async (filters?: TeamFilters) => {
    try {
      setLoading(true);
      setError(null);
      const params: Record<string, any> = {};
      if (filters?.department_id) params.department_id = filters.department_id;
      if (filters?.active !== undefined) params.active = filters.active;
      if (filters?.with_members) params.with_members = true;
      if (filters?.with_roles) params.with_roles = true;
      if (filters?.search) params.search = filters.search;

      const response = await axios.get(`${API_BASE}/teams`, { params });
      setTeams(response.data.data || response.data);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load teams');
      console.error('Error fetching teams:', err);
    } finally {
      setLoading(false);
    }
  }, []);

  const create = useCallback(async (data: TeamFormData): Promise<Team> => {
    const response = await axios.post(`${API_BASE}/teams`, data);
    await refresh();
    return response.data;
  }, [refresh]);

  const update = useCallback(async (id: number, data: Partial<TeamFormData>): Promise<Team> => {
    const response = await axios.put(`${API_BASE}/teams/${id}`, data);
    await refresh();
    return response.data;
  }, [refresh]);

  const remove = useCallback(async (id: number): Promise<void> => {
    await axios.delete(`${API_BASE}/teams/${id}`);
    await refresh();
  }, [refresh]);

  const getById = useCallback(async (id: number): Promise<Team> => {
    const response = await axios.get(`${API_BASE}/teams/${id}`);
    return response.data;
  }, []);

  const getMembers = useCallback(async (teamId: number): Promise<SystemUser[]> => {
    const response = await axios.get(`${API_BASE}/teams/${teamId}/members`);
    return response.data.data || response.data;
  }, []);

  const addMember = useCallback(async (teamId: number, data: TeamMemberFormData): Promise<void> => {
    await axios.post(`${API_BASE}/teams/${teamId}/members`, data);
  }, []);

  const updateMember = useCallback(async (teamId: number, userId: number, data: UpdateTeamMemberRequest): Promise<void> => {
    await axios.put(`${API_BASE}/teams/${teamId}/members/${userId}`, data);
  }, []);

  const removeMember = useCallback(async (teamId: number, userId: number): Promise<void> => {
    await axios.delete(`${API_BASE}/teams/${teamId}/members/${userId}`);
  }, []);

  const syncRoles = useCallback(async (teamId: number, roleIds: number[]): Promise<void> => {
    await axios.post(`${API_BASE}/teams/${teamId}/roles`, { role_ids: roleIds });
    await refresh({ with_roles: true });
  }, [refresh]);

  useEffect(() => {
    refresh({ with_members: true, with_roles: true });
  }, []);

  return {
    teams,
    loading,
    error,
    refresh,
    create,
    update,
    remove,
    getById,
    getMembers,
    addMember,
    updateMember,
    removeMember,
    syncRoles,
  };
}

// ============================================================
// Combined Permission Graph Hook (for canvas visualization)
// ============================================================
interface UsePermissionGraphReturn {
  // Data
  permissions: Permission[];
  roles: SystemRole[];
  teams: Team[];
  users: SystemUser[];
  // Loading
  loading: boolean;
  error: string | null;
  // Actions
  refreshAll: () => Promise<void>;
  // Role-Permission management
  addPermissionToRole: (roleId: number, permissionId: number) => Promise<void>;
  removePermissionFromRole: (roleId: number, permissionId: number) => Promise<void>;
  // Team-Role management
  addRoleToTeam: (teamId: number, roleId: number) => Promise<void>;
  removeRoleFromTeam: (teamId: number, roleId: number) => Promise<void>;
  // Team-Member management
  addMemberToTeam: (teamId: number, userId: number, isLead?: boolean) => Promise<void>;
  removeMemberFromTeam: (teamId: number, userId: number) => Promise<void>;
}

export function usePermissionGraph(): UsePermissionGraphReturn {
  const [permissions, setPermissions] = useState<Permission[]>([]);
  const [roles, setRoles] = useState<SystemRole[]>([]);
  const [teams, setTeams] = useState<Team[]>([]);
  const [users, setUsers] = useState<SystemUser[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const refreshAll = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);

      const [permRes, rolesRes, teamsRes, usersRes] = await Promise.all([
        axios.get(`${API_BASE}/permissions`),
        axios.get(`${API_BASE}/roles`, { params: { with_permissions: true } }),
        axios.get(`${API_BASE}/teams`, { params: { with_members: true, with_roles: true } }),
        axios.get('/zeiterfassung/users'), // Existing users endpoint
      ]);

      setPermissions(permRes.data.data || permRes.data);
      setRoles(rolesRes.data.data || rolesRes.data);
      setTeams(teamsRes.data.data || teamsRes.data);
      setUsers(usersRes.data.data || usersRes.data);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load permission graph data');
      console.error('Error fetching permission graph:', err);
    } finally {
      setLoading(false);
    }
  }, []);

  const addPermissionToRole = useCallback(async (roleId: number, permissionId: number) => {
    const role = roles.find(r => r.role_id === roleId);
    if (!role) return;

    const currentPermIds = role.permissions?.map(p => p.perm_id) || [];
    if (currentPermIds.includes(permissionId)) return;

    await axios.post(`${API_BASE}/roles/${roleId}/permissions`, {
      permission_ids: [...currentPermIds, permissionId],
    });
    await refreshAll();
  }, [roles, refreshAll]);

  const removePermissionFromRole = useCallback(async (roleId: number, permissionId: number) => {
    const role = roles.find(r => r.role_id === roleId);
    if (!role) return;

    const currentPermIds = role.permissions?.map(p => p.perm_id) || [];
    const newPermIds = currentPermIds.filter(id => id !== permissionId);

    await axios.post(`${API_BASE}/roles/${roleId}/permissions`, {
      permission_ids: newPermIds,
    });
    await refreshAll();
  }, [roles, refreshAll]);

  const addRoleToTeam = useCallback(async (teamId: number, roleId: number) => {
    const team = teams.find(t => t.team_id === teamId);
    if (!team) return;

    const currentRoleIds = team.roles?.map(r => r.role_id) || [];
    if (currentRoleIds.includes(roleId)) return;

    await axios.post(`${API_BASE}/teams/${teamId}/roles`, {
      role_ids: [...currentRoleIds, roleId],
    });
    await refreshAll();
  }, [teams, refreshAll]);

  const removeRoleFromTeam = useCallback(async (teamId: number, roleId: number) => {
    const team = teams.find(t => t.team_id === teamId);
    if (!team) return;

    const currentRoleIds = team.roles?.map(r => r.role_id) || [];
    const newRoleIds = currentRoleIds.filter(id => id !== roleId);

    await axios.post(`${API_BASE}/teams/${teamId}/roles`, {
      role_ids: newRoleIds,
    });
    await refreshAll();
  }, [teams, refreshAll]);

  const addMemberToTeam = useCallback(async (teamId: number, userId: number, isLead = false) => {
    await axios.post(`${API_BASE}/teams/${teamId}/members`, {
      user_id: userId,
      is_lead: isLead,
    });
    await refreshAll();
  }, [refreshAll]);

  const removeMemberFromTeam = useCallback(async (teamId: number, userId: number) => {
    await axios.delete(`${API_BASE}/teams/${teamId}/members/${userId}`);
    await refreshAll();
  }, [refreshAll]);

  useEffect(() => {
    refreshAll();
  }, []);

  return {
    permissions,
    roles,
    teams,
    users,
    loading,
    error,
    refreshAll,
    addPermissionToRole,
    removePermissionFromRole,
    addRoleToTeam,
    removeRoleFromTeam,
    addMemberToTeam,
    removeMemberFromTeam,
  };
}

export default usePermissions;
