import { create } from 'zustand';
import { api } from '../api/client';
import { config } from '../config';

interface AuthState {
  accessToken: string | null;
  refreshToken: string | null;
  username: string | null;
  roles: string[];
  isAuthenticated: boolean;
  error: string | null;
  loading: boolean;
  login: (username: string, password: string) => Promise<void>;
  loginWithOidcCode: (code: string, redirectUri: string) => Promise<void>;
  refresh: () => Promise<boolean>;
  logout: () => void;
}

function parseRolesFromJwt(token: string): string[] {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    return Array.isArray(payload.roles) ? payload.roles : [];
  } catch {
    return [];
  }
}

function loadTokens() {
  return {
    accessToken: localStorage.getItem('cameleer-access-token'),
    refreshToken: localStorage.getItem('cameleer-refresh-token'),
    username: localStorage.getItem('cameleer-username'),
  };
}

function persistTokens(access: string, refresh: string, username: string) {
  localStorage.setItem('cameleer-access-token', access);
  localStorage.setItem('cameleer-refresh-token', refresh);
  localStorage.setItem('cameleer-username', username);
}

function clearTokens() {
  localStorage.removeItem('cameleer-access-token');
  localStorage.removeItem('cameleer-refresh-token');
  localStorage.removeItem('cameleer-username');
}

const initial = loadTokens();

export const useAuthStore = create<AuthState>((set, get) => ({
  accessToken: initial.accessToken,
  refreshToken: initial.refreshToken,
  username: initial.username,
  roles: initial.accessToken ? parseRolesFromJwt(initial.accessToken) : [],
  isAuthenticated: !!initial.accessToken,
  error: null,
  loading: false,

  login: async (username, password) => {
    set({ loading: true, error: null });
    try {
      const { data, error } = await api.POST('/auth/login', {
        body: { username, password },
      });
      if (error || !data) {
        throw new Error('Invalid credentials');
      }
      const { accessToken, refreshToken, displayName } = data;
      localStorage.removeItem('cameleer-oidc-end-session');
      localStorage.removeItem('cameleer-oidc-id-token');
      const name = displayName ?? username;
      persistTokens(accessToken, refreshToken, name);
      set({
        accessToken,
        refreshToken,
        username: name,
        roles: parseRolesFromJwt(accessToken),
        isAuthenticated: true,
        loading: false,
      });
    } catch (e: unknown) {
      set({
        error: e instanceof Error ? e.message : 'Login failed',
        loading: false,
      });
    }
  },

  loginWithOidcCode: async (code, redirectUri) => {
    set({ loading: true, error: null });
    try {
      const { data, error } = await api.POST('/auth/oidc/callback', {
        body: { code, redirectUri },
      });
      if (error || !data) {
        throw new Error('OIDC login failed');
      }
      const { accessToken, refreshToken, displayName, idToken } = data;
      const username = displayName ?? 'oidc-user';
      persistTokens(accessToken, refreshToken, username);
      if (idToken) {
        localStorage.setItem('cameleer-oidc-id-token', idToken);
      }
      set({
        accessToken,
        refreshToken,
        username,
        roles: parseRolesFromJwt(accessToken),
        isAuthenticated: true,
        loading: false,
      });
    } catch (e: unknown) {
      set({
        error: e instanceof Error ? e.message : 'OIDC login failed',
        loading: false,
      });
    }
  },

  refresh: async () => {
    const { refreshToken } = get();
    if (!refreshToken) return false;
    try {
      const { data, error } = await api.POST('/auth/refresh', {
        body: { refreshToken },
      });
      if (error || !data) return false;
      const username = data.displayName ?? get().username ?? '';
      persistTokens(data.accessToken, data.refreshToken, username);
      set({
        accessToken: data.accessToken,
        refreshToken: data.refreshToken,
        username,
        roles: parseRolesFromJwt(data.accessToken),
        isAuthenticated: true,
      });
      return true;
    } catch {
      return false;
    }
  },

  logout: () => {
    const endSessionEndpoint = localStorage.getItem('cameleer-oidc-end-session');
    const idToken = localStorage.getItem('cameleer-oidc-id-token');
    clearTokens();
    localStorage.removeItem('cameleer-oidc-end-session');
    localStorage.removeItem('cameleer-oidc-id-token');
    set({
      accessToken: null,
      refreshToken: null,
      username: null,
      roles: [],
      isAuthenticated: false,
      error: null,
    });
    const loginUrl = `${config.basePath}login?local`;
    if (endSessionEndpoint && idToken) {
      const params = new URLSearchParams({
        id_token_hint: idToken,
        post_logout_redirect_uri: `${window.location.origin}${config.basePath}login?local`,
      });
      fetch(`${endSessionEndpoint}?${params}`, { mode: 'no-cors' }).finally(() => {
        window.location.href = loginUrl;
      });
    } else {
      window.location.href = loginUrl;
    }
  },
}));

export const useIsAdmin = () => useAuthStore((s) => s.roles.some(r => r === 'ADMIN'));
export const useCanControl = () => useAuthStore((s) => s.roles.some(r => r === 'OPERATOR' || r === 'ADMIN'));
