import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";

// Define the initial state for the authentication slice
interface AuthState {
  isLoggedIn: boolean;
  authMessage: string;
  status: "idle" | "loading" | "succeeded" | "failed";
  error: string | null;
  user: {
    email: string;
    role: string;
  } | null;
  tokenInfo: {
    expiresAt: string;
    timeUntilExpiration: number;
    expiresInHours: number;
  } | null;
}

const initialState: AuthState = {
  isLoggedIn: false,
  authMessage: "",
  status: "idle",
  error: null,
  user: null,
  tokenInfo: null,
};

// Async Thunk for Login
// This handles the API call to your Next.js login Route Handler
export const login = createAsyncThunk(
  "auth/login",
  async (
    { email, password }: { email: string; password: string },
    { rejectWithValue }
  ) => {
    try {
      const response = await fetch("/api/auth/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ email, password }),
      });

      const data = await response.json();

      if (!response.ok) {
        // If the server responded with an error status (e.g., 401, 400, 500)
        return rejectWithValue(data.message || "Login failed");
      }

      // On successful login, the backend sets the HTTP-only cookie.
      // We'll set a client-side flag (like localStorage) for immediate UI updates,
      // though the primary source of truth for auth is the HTTP-only cookie.
      if (typeof window !== "undefined") {
        // Ensure localStorage access is client-side
        localStorage.setItem("userToken", "mock-authenticated"); // For client-side state sync
      }

      // After successful login, check auth status to get token information
      // This ensures we have the token expiration details immediately
      const authStatusResponse = await fetch("/api/auth/status");
      if (authStatusResponse.ok) {
        const authData = await authStatusResponse.json();
        return {
          message: data.message || "Login successful",
          user: authData.user,
          tokenInfo: authData.tokenInfo,
        };
      }

      return data.message || "Login successful";
    } catch (error: unknown) {
      // Handle network errors or other unexpected issues
      const errorMessage =
        error instanceof Error ? error.message : "Network error during login";
      return rejectWithValue(errorMessage);
    }
  }
);

// Async Thunk for Logout
// This handles the API call to your Next.js logout Route Handler
export const logout = createAsyncThunk(
  "auth/logout",
  async (_, { rejectWithValue }) => {
    try {
      const response = await fetch("/api/auth/logout", {
        method: "DELETE",
      });

      const data = await response.json();

      if (!response.ok) {
        // If the server responded with an error status
        return rejectWithValue(data.message || "Logout failed");
      }

      if (typeof window !== "undefined") {
        // Ensure localStorage access is client-side
        localStorage.removeItem("userToken"); // Clear client-side flag
      }

      // After successful logout, check auth status to ensure proper cleanup
      const authStatusResponse = await fetch("/api/auth/status");
      if (authStatusResponse.ok) {
        const authData = await authStatusResponse.json();
        return {
          message: data.message || "Logged out successfully",
          isAuthenticated: authData.isAuthenticated,
        };
      }

      return data.message || "Logged out successfully";
    } catch (error: unknown) {
      // Handle network errors
      const errorMessage =
        error instanceof Error ? error.message : "Network error during logout";
      return rejectWithValue(errorMessage);
    }
  }
);

// Async Thunk for automatic logout (when token expires)
export const autoLogout = createAsyncThunk(
  "auth/autoLogout",
  async (reason: string, { rejectWithValue }) => {
    try {
      // Clear the cookie by calling logout endpoint
      await fetch("/api/auth/logout", {
        method: "DELETE",
      });

      if (typeof window !== "undefined") {
        // Clear client-side storage
        localStorage.removeItem("userToken");
      }

      return { message: `Auto-logout: ${reason}` };
    } catch (error: unknown) {
      const errorMessage =
        error instanceof Error ? error.message : "Auto-logout failed";
      return rejectWithValue(errorMessage);
    }
  }
);

// Async Thunk for manual refresh of authentication status
export const refreshAuthStatus = createAsyncThunk(
  "auth/refreshStatus",
  async (_, { rejectWithValue }) => {
    try {
      const response = await fetch("/api/auth/status");
      const data = await response.json();

      if (!response.ok) {
        return rejectWithValue(data.message || "Authentication refresh failed");
      }

      return data;
    } catch (error: unknown) {
      const errorMessage =
        error instanceof Error
          ? error.message
          : "Network error during auth refresh";
      return rejectWithValue(errorMessage);
    }
  }
);

// Async Thunk for checking authentication status
export const checkAuthStatus = createAsyncThunk(
  "auth/checkStatus",
  async (_, { rejectWithValue }) => {
    try {
      const response = await fetch("/api/auth/status");
      const data = await response.json();

      if (!response.ok) {
        return rejectWithValue(data.message || "Authentication check failed");
      }

      return data;
    } catch (error: unknown) {
      const errorMessage =
        error instanceof Error
          ? error.message
          : "Network error during auth check";
      return rejectWithValue(errorMessage);
    }
  }
);

// Create the authentication slice
const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    // Reducer to set an authentication message (e.g., from UI actions)
    setAuthMessage: (state, action: PayloadAction<string>) => {
      state.authMessage = action.payload;
    },
    // Reducer to clear the authentication message
    clearAuthMessage: (state) => {
      state.authMessage = "";
    },
    // Reducer to initialize login status from client-side storage (e.g., on app load)
    // This is useful for cases where middleware might not redirect immediately,
    // or for client-side rendering of protected content based on initial state.
    initializeAuth: (state) => {
      if (typeof window !== "undefined") {
        // Ensure this runs only on the client
        const userToken = localStorage.getItem("userToken");
        state.isLoggedIn = userToken === "mock-authenticated";
      }
    },
  },
  extraReducers: (builder) => {
    builder
      // Login Thunk Reducers
      .addCase(login.pending, (state) => {
        state.status = "loading";
        state.error = null;
        state.authMessage = "Attempting login...";
      })
      .addCase(login.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.isLoggedIn = true;
        // Handle both old string payload and new object payload
        if (typeof action.payload === "string") {
          state.authMessage = action.payload;
        } else {
          state.authMessage = action.payload.message;
          state.user = action.payload.user || null;
          state.tokenInfo = action.payload.tokenInfo || null;
        }
      })
      .addCase(login.rejected, (state, action) => {
        state.status = "failed";
        state.isLoggedIn = false;
        state.error = action.payload as string;
        state.authMessage = action.payload as string; // Display error message
      })
      // Logout Thunk Reducers
      .addCase(logout.pending, (state) => {
        state.status = "loading";
        state.error = null;
        state.authMessage = "Logging out...";
      })
      .addCase(logout.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.isLoggedIn = false;
        // Handle both old string payload and new object payload
        if (typeof action.payload === "string") {
          state.authMessage = action.payload;
        } else {
          state.authMessage = action.payload.message;
          // Ensure we're properly logged out
          if (action.payload.isAuthenticated === false) {
            state.user = null;
            state.tokenInfo = null;
          }
        }
        // Always clear user data on logout
        state.user = null;
        state.tokenInfo = null;
      })
      .addCase(logout.rejected, (state, action) => {
        state.status = "failed";
        state.isLoggedIn = true; // Stay logged in if logout failed
        state.error = action.payload as string;
        state.authMessage = action.payload as string; // Display error message
      })
      // Check Auth Status Thunk Reducers
      .addCase(checkAuthStatus.pending, (state) => {
        state.status = "loading";
        state.error = null;
      })
      .addCase(checkAuthStatus.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.isLoggedIn = action.payload.isAuthenticated;
        state.user = action.payload.user || null;
        state.tokenInfo = action.payload.tokenInfo || null;
        state.error = null;
      })
      .addCase(checkAuthStatus.rejected, (state, action) => {
        state.status = "failed";
        state.isLoggedIn = false;
        state.user = null;
        state.tokenInfo = null;
        state.error = action.payload as string;
      })
      // Auto Logout Thunk Reducers
      .addCase(autoLogout.pending, (state) => {
        state.status = "loading";
        state.error = null;
        state.authMessage = "Session expired, logging out...";
      })
      .addCase(autoLogout.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.isLoggedIn = false;
        state.authMessage = action.payload.message;
        state.user = null;
        state.tokenInfo = null;
        state.error = null;
      })
      .addCase(autoLogout.rejected, (state, action) => {
        state.status = "failed";
        state.isLoggedIn = false;
        state.user = null;
        state.tokenInfo = null;
        state.error = action.payload as string;
        state.authMessage = "Auto-logout failed";
      })
      // Refresh Auth Status Thunk Reducers
      .addCase(refreshAuthStatus.pending, (state) => {
        state.status = "loading";
        state.error = null;
      })
      .addCase(refreshAuthStatus.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.isLoggedIn = action.payload.isAuthenticated;
        state.user = action.payload.user || null;
        state.tokenInfo = action.payload.tokenInfo || null;
        state.error = null;
      })
      .addCase(refreshAuthStatus.rejected, (state, action) => {
        state.status = "failed";
        state.isLoggedIn = false;
        state.user = null;
        state.tokenInfo = null;
        state.error = action.payload as string;
      });
  },
});

export const { setAuthMessage, clearAuthMessage, initializeAuth } =
  authSlice.actions;

export default authSlice.reducer;
