/**
 * SSO Service for Median Cloud (https://auth.median-cloud.web.id)
 * Python Django 5.x OAuth2 / OIDC Server Handshake & JWT Token Engine
 * PT Media Ekosistem Digital Aplikasi Nasional (MEDIAN CLOUD)
 */

import { Employee } from '../types';

export const SSO_AUTH_SERVER_URL = "https://auth.median-cloud.web.id";
export const SSO_PORTAL_URL = "https://median-cloud.web.id";
export const SSO_CLIENT_ID = "ems-gan-django-client";

// Storage & Event Constants
export const SSO_STORAGE_KEYS = {
  TOKEN: "median_sso_jwt_token",
  REFRESH_TOKEN: "median_sso_refresh_token",
  USER_SESSION: "median_sso_session",
  AUTH_STATE: "median_sso_auth_state",
  CURRENT_USER_ID: "current_user_id",
  EXPIRY_TIMESTAMP: "median_sso_token_exp"
} as const;

export const SSO_EVENTS = {
  SESSION_CHANGED: "median_sso_session_changed",
  TOKEN_EXPIRED: "median_sso_token_expired",
  LOGOUT: "median_sso_logout"
} as const;

/**
 * Interface representing decoded SSO User info payload from Django OAuth / JWT
 */
export interface SsoUserPayload {
  ssoId: string;
  name: string;
  email: string;
  nip: string;
  nik: string;
  position: string;
  division: string;
  avatarUrl?: string;
  providerUrl: string;
  tenantId?: string;
  tenantDomain?: string;
  tenantSubdomain?: string;
  tenantCompanyName?: string;
  tenantPlan?: string;
  membershipRole?: string;
  permissions?: string[];
  roles?: string[];
  department?: string;
  phone?: string;
  authenticatedAt: string;
  exp?: number;
  iat?: number;
  iss?: string;
  aud?: string;
}

/**
 * Interface for Raw Standard JWT Token Claims
 */
export interface JwtClaims {
  sub?: string;
  iss?: string;
  aud?: string | string[];
  exp?: number;
  nbf?: number;
  iat?: number;
  jti?: string;
  name?: string;
  email?: string;
  nip?: string;
  nik?: string;
  position?: string;
  division?: string;
  department?: string;
  roles?: string[];
  [key: string]: any;
}

/**
 * Authorization URL Options
 */
export interface SsoAuthOptions {
  redirectUri?: string;
  scope?: string;
  state?: string;
  prompt?: 'login' | 'consent' | 'select_account';
  responseType?: 'code' | 'token';
}

/**
 * Token Verification Result
 */
export interface TokenVerificationResult {
  isValid: boolean;
  isExpired: boolean;
  expiresInSeconds?: number;
  payload?: JwtClaims | null;
  error?: string;
}

/**
 * Active SSO Auth State
 */
export interface SsoAuthState {
  isAuthenticated: boolean;
  user: SsoUserPayload | null;
  token: string | null;
  expiresAt: number | null;
  isExpired: boolean;
}

class SsoService {
  private authServerUrl: string = SSO_AUTH_SERVER_URL;
  private portalUrl: string = SSO_PORTAL_URL;
  private clientId: string = SSO_CLIENT_ID;

  constructor() {
    this.setupStorageEventListener();
  }

  // =========================================================================
  // 1. REDIRECTION & OAUTH AUTHORIZATION URL GENERATION
  // =========================================================================

  /**
   * Constructs the full authorization URL for auth.median-cloud.web.id
   */
  public async getAuthorizationUrl(options?: SsoAuthOptions): Promise<string> {
    const origin = typeof window !== 'undefined' ? window.location.origin : 'https://ems.median-cloud.web.id';
    const targetRedirect = options?.redirectUri || `${origin}/auth/callback`;
    const state = options?.state || `sso_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;

    // Store state in sessionStorage for CSRF protection
    if (typeof window !== 'undefined') {
      sessionStorage.setItem(SSO_STORAGE_KEYS.AUTH_STATE, state);
    }

    try {
      // Attempt to retrieve pre-configured URL from backend API route if available
      const res = await fetch(`/api/auth/median/url?redirect_uri=${encodeURIComponent(targetRedirect)}`);
      if (res.ok) {
        const data = await res.json();
        if (data.url) return data.url;
      }
    } catch (err) {
      console.warn("[SsoService] Backend auth URL endpoint unavailable, building direct Django URL:", err);
    }

    const params = new URLSearchParams({
      client_id: this.clientId,
      redirect_uri: targetRedirect,
      response_type: options?.responseType || "code",
      scope: options?.scope || "openid profile email nip division position",
      state: state
    });

    if (options?.prompt) {
      params.set('prompt', options.prompt);
    }

    return `${this.authServerUrl}/o/authorize/?${params.toString()}`;
  }

  /**
   * Redirects the entire browser window to https://auth.median-cloud.web.id for authentication
   */
  public async redirectToLogin(options?: SsoAuthOptions): Promise<void> {
    if (typeof window === 'undefined') return;
    const returnPath = `${window.location.pathname}${window.location.search}${window.location.hash}` || "/";
    window.location.href = `/auth/login?return=${encodeURIComponent(returnPath)}`;
  }

  /**
   * Launches a centered OAuth popup window for seamless in-app authentication
   */
  public async launchOauthPopup(
    onSuccess: (user: SsoUserPayload, token?: string) => void,
    onError: (errorMsg: string) => void,
    options?: SsoAuthOptions
  ): Promise<Window | null> {
    if (typeof window === 'undefined') return null;

    try {
      const res = await fetch(`/api/auth/median/url?mode=popup&return=${encodeURIComponent(window.location.pathname || "/")}`, { credentials: "same-origin", cache: "no-store" });
      if (!res.ok) throw new Error(`Gateway SSO gagal (HTTP ${res.status})`);
      const data = await res.json();
      if (!data.url) throw new Error("Gateway SSO tidak mengembalikan authorization URL.");
      const authUrl = String(data.url);

      const width = 620;
      const height = 720;
      const left = window.screenX + (window.outerWidth - width) / 2;
      const top = window.screenY + (window.outerHeight - height) / 2;

      const popup = window.open(
        authUrl,
        "median_cloud_sso_popup",
        `width=${width},height=${height},top=${top},left=${left},scrollbars=yes,status=yes`
      );

      if (!popup) {
        const msg = "Popup browser diblokir! Harap izinkan popup di browser untuk login dengan Median Cloud SSO (https://auth.median-cloud.web.id).";
        onError(msg);
        return null;
      }

      // Check for popup closure
      const timer = setInterval(() => {
        if (popup.closed) {
          clearInterval(timer);
        }
      }, 1000);

      return popup;
    } catch (err: any) {
      const msg = `Gagal membuka jendela autentikasi SSO: ${err.message || err}`;
      onError(msg);
      return null;
    }
  }

  // =========================================================================
  // 2. JWT TOKEN PARSING & VERIFICATION LOGIC
  // =========================================================================

  /**
   * Safely decodes base64 / base64url string with UTF-8 support
   */
  private decodeBase64Url(str: string): string {
    let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
    while (base64.length % 4) {
      base64 += '=';
    }
    try {
      const binaryStr = atob(base64);
      const bytes = new Uint8Array(binaryStr.length);
      for (let i = 0; i < binaryStr.length; i++) {
        bytes[i] = binaryStr.charCodeAt(i);
      }
      return new TextDecoder().decode(bytes);
    } catch (e) {
      return atob(base64);
    }
  }

  /**
   * Decodes JWT token payload without signature verification (safe for client inspection)
   */
  public decodeJwt<T = JwtClaims>(token: string): T | null {
    if (!token || typeof token !== 'string') return null;

    try {
      const parts = token.trim().split('.');
      if (parts.length !== 3) {
        return null;
      }

      const payloadJson = this.decodeBase64Url(parts[1]);
      return JSON.parse(payloadJson) as T;
    } catch (err) {
      console.warn("[SsoService] Failed to parse JWT token payload:", err);
      return null;
    }
  }

  /**
   * Validates JWT token format, issuer, timestamp claims (iat, exp), and remaining TTL
   */
  public verifyToken(token: string): TokenVerificationResult {
    if (!token || typeof token !== 'string') {
      return { isValid: false, isExpired: true, error: "Token string kosong atau tidak valid" };
    }

    const parts = token.trim().split('.');
    if (parts.length !== 3) {
      return { isValid: false, isExpired: true, error: "Format JWT tidak valid (harus 3 segmen terpisah titik)" };
    }

    const payload = this.decodeJwt<JwtClaims>(token);
    if (!payload) {
      return { isValid: false, isExpired: true, error: "Gagal mendecode payload JWT token" };
    }

    const nowSeconds = Math.floor(Date.now() / 1000);

    // Check expiration claim (exp)
    if (typeof payload.exp === 'number') {
      if (payload.exp < nowSeconds) {
        return {
          isValid: false,
          isExpired: true,
          expiresInSeconds: 0,
          payload,
          error: `Token JWT telah kedaluwarsa pada ${new Date(payload.exp * 1000).toLocaleString()}`
        };
      }

      const expiresInSeconds = payload.exp - nowSeconds;
      return {
        isValid: true,
        isExpired: false,
        expiresInSeconds,
        payload
      };
    }

    // If no exp claim exists, token structure is valid
    return {
      isValid: true,
      isExpired: false,
      payload
    };
  }

  /**
   * Performs server-side cryptographic token verification via backend proxy
   */
  public async verifyTokenWithServer(token: string): Promise<{ success: boolean; user?: SsoUserPayload; message?: string }> {
    try {
      const res = await fetch("/api/auth/median/verify", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ token })
      });

      if (!res.ok) {
        const errorData = await res.json().catch(() => ({}));
        return { success: false, message: errorData.error || `Server verification failed with HTTP ${res.status}` };
      }

      const data = await res.json();
      return {
        success: true,
        user: data.ssoUser,
        message: data.message || "Token berhasil diverifikasi oleh server"
      };
    } catch (err: any) {
      console.warn("[SsoService] Server-side verification network error:", err);
      return { success: false, message: err.message || "Gagal memverifikasi server-side SSO session" };
    }
  }

  /**
   * Helper to map JWT Claims to standard SsoUserPayload
   */
  public mapClaimsToSsoUser(claims: JwtClaims): SsoUserPayload {
    return {
      ssoId: claims.sub || claims.ssoId || `django-usr-${Date.now()}`,
      name: claims.name || claims.username || claims.email || "Tenant User",
      email: claims.email || "",
      nip: claims.nip || "",
      nik: claims.nik || "",
      position: claims.position || "Tenant User",
      division: claims.division || claims.department || "Tenant",
      providerUrl: claims.iss || this.authServerUrl,
      tenantId: claims.tenantId || claims.client_tenant_id || undefined,
      roles: claims.roles || claims.ems_roles || [],
      authenticatedAt: new Date().toISOString(),
      exp: claims.exp,
      iat: claims.iat
    };
  }

  // =========================================================================
  // 3. USER SESSION SYNCHRONIZATION WITH CURRENT APP STATE
  // =========================================================================

  /**
   * Synchronizes SSO User with Local Storage, App State, and matches with Employee records
   */
  public syncSessionWithAppState(
    ssoUser: SsoUserPayload,
    employees?: Employee[],
    token?: string
  ): { matchedEmployee: Employee; ssoUser: SsoUserPayload } {
    // 1. Save session to localStorage
    this.saveSession(ssoUser, token);

    // 2. Match with employee record in app state
    let matchedEmployee: Employee | undefined;

    if (employees && Array.isArray(employees) && employees.length > 0) {
      matchedEmployee = employees.find(
        e => (e.nip && e.nip === ssoUser.nip) ||
             (e.email && ssoUser.email && e.email.toLowerCase() === ssoUser.email.toLowerCase()) ||
             (e.name && ssoUser.name && e.name.toLowerCase() === ssoUser.name.toLowerCase())
      );
    }

    // 3. If employee is found, merge updated SSO data
    if (matchedEmployee) {
      matchedEmployee = {
        ...matchedEmployee,
        email: ssoUser.email || matchedEmployee.email,
        position: ssoUser.position || matchedEmployee.position,
        division: ssoUser.division || matchedEmployee.division
      };
    } else {
      // 4. If employee record does not exist yet, dynamically synthesize a compliant Employee object
      matchedEmployee = this.createSyntheticEmployee(ssoUser);
    }

    // 5. Store current user ID in localStorage
    if (typeof window !== 'undefined') {
      localStorage.setItem(SSO_STORAGE_KEYS.CURRENT_USER_ID, matchedEmployee.id);
    }

    // 6. Broadcast event across tabs and components
    this.broadcastSessionChange(ssoUser);

    return {
      matchedEmployee,
      ssoUser
    };
  }

  /**
   * Generates a fully valid Employee record from SSO payload for seamless state integration
   */
  public createSyntheticEmployee(ssoUser: SsoUserPayload): Employee {
    const isCeo = false;

    return {
      id: `emp-sso-${ssoUser.ssoId || ssoUser.nip || Date.now()}`,
      tenantId: ssoUser.tenantId || "",
      nip: ssoUser.nip || "",
      nik: ssoUser.nik || "",
      name: ssoUser.name || "Tenant User",
      photoUrl: ssoUser.avatarUrl || "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&auto=format&fit=crop&q=80",
      division: ssoUser.division || "Tenant",
      position: ssoUser.position || "Tenant User",
      status: "Tetap",
      tmtKerja: "2015-01-01",
      birthPlace: "Jakarta",
      birthDate: "1975-05-15",
      reportingTo: isCeo ? "none" : "emp-ceo-01",
      phone: ssoUser.phone || "",
      email: ssoUser.email || "",
      address: "MEDIAN Cloud Tower, Lt. 18-20, Jl. Jend. Sudirman Kav. 52-53, Jakarta Selatan",
      gender: "L",
      kpiScore: 98,
      salarySettings: {
        payGrade: isCeo ? "Grade 10 - Executive Director" : "Grade 8 - General Manager",
        baseSalary: isCeo ? 45000000 : 25000000,
        positionAllowance: isCeo ? 15000000 : 8000000,
        transportAllowance: 3000000,
        mealAllowance: 2000000,
        communicationAllowance: 1500000,
        performanceBonus: 5000000,
        overtimeHours: 0,
        overtimeRatePerHour: 0,
        taxStatus: "K/2",
        taxRatePercent: 5,
        bpjsKesehatanPercent: 1,
        bpjsKetenagakerjaanPercent: 3,
        customAllowances: [],
        customDeductions: [],
        bankName: "Bank Mandiri",
        bankAccountNumber: "123-00-9876543-2",
        bankAccountHolder: ssoUser.name
      },
      riwayatJabatan: [
        {
          id: `rj-sso-1`,
          date: "2026-01-01",
          type: "Pengangkatan",
          position: ssoUser.position,
          division: ssoUser.division,
          note: "Pengangkatan via Median Cloud SSO Provider Integration"
        }
      ],
      riwayatPendidikan: [
        {
          id: `rp-sso-1`,
          level: "S2",
          school: "Institut Teknologi Bandung (ITB)",
          major: "Magister Manajemen Sistem Informasi",
          yearGraduated: "2008"
        }
      ],
      riwayatPelatihan: [
        {
          id: `rpel-sso-1`,
          date: "2025-06-15",
          course: "Enterprise Architecture & SSO Security Leadership",
          provider: "Cloud & Digital Governance Institute",
          category: "Leadership",
          certificateNo: "CERT/MEDIAN/SSO/2025"
        }
      ],
      riwayatSK: [],
      riwayatKPI: [],
      riwayatReward: [],
      riwayatPunishment: [],
      timeline: [],
      documents: []
    };
  }

  /**
   * Persists session information and tokens to LocalStorage
   */
  public saveSession(user: SsoUserPayload, token?: string, refreshToken?: string): void {
    if (typeof window === 'undefined') return;

    try {
      localStorage.setItem(SSO_STORAGE_KEYS.USER_SESSION, JSON.stringify(user));
      localStorage.setItem(SSO_STORAGE_KEYS.CURRENT_USER_ID, user.nip || user.ssoId);

      // OAuth access/refresh tokens are deliberately never persisted in the browser.
      // The production tenant gateway stores them server-side in an HttpOnly session.
      localStorage.removeItem(SSO_STORAGE_KEYS.TOKEN);
      localStorage.removeItem(SSO_STORAGE_KEYS.REFRESH_TOKEN);
      localStorage.removeItem(SSO_STORAGE_KEYS.EXPIRY_TIMESTAMP);
    } catch (e) {
      console.error("[SsoService] Failed to persist session to localStorage:", e);
    }
  }

  /**
   * Bootstraps identity from the production gateway HttpOnly session.
   * No OAuth token is exposed to JavaScript.
   */
  public async fetchServerSession(): Promise<{ authenticated: boolean; user?: SsoUserPayload; tenant?: any; message?: string }> {
    try {
      const res = await fetch("/api/session", { credentials: "same-origin", cache: "no-store", headers: { Accept: "application/json" } });
      const data = await res.json().catch(() => ({}));
      if (!res.ok || !data.authenticated || !data.user) {
        return { authenticated: false, message: data.message || `HTTP ${res.status}` };
      }
      return { authenticated: true, user: data.user as SsoUserPayload, tenant: data.tenant };
    } catch (error: any) {
      return { authenticated: false, message: error?.message || "Gateway session tidak tersedia" };
    }
  }

  /**
   * Retrieves the current stored user session (alias: getActiveSession)
   */
  public getStoredSession(): SsoUserPayload | null {
    if (typeof window === 'undefined') return null;

    try {
      const raw = localStorage.getItem(SSO_STORAGE_KEYS.USER_SESSION);
      if (!raw) return null;
      return JSON.parse(raw) as SsoUserPayload;
    } catch (e) {
      console.warn("[SsoService] Failed to parse stored user session:", e);
      return null;
    }
  }

  /**
   * Alias for getStoredSession()
   */
  public getActiveSession(): SsoUserPayload | null {
    return this.getStoredSession();
  }

  /**
   * Retrieves the stored JWT access token
   */
  public getStoredToken(): string | null {
    if (typeof window === 'undefined') return null;
    return localStorage.getItem(SSO_STORAGE_KEYS.TOKEN);
  }

  /**
   * Returns current authentication state
   */
  public getAuthState(): SsoAuthState {
    const user = this.getStoredSession();
    const token = this.getStoredToken();

    let isExpired = false;
    let expiresAt: number | null = null;

    if (token) {
      const check = this.verifyToken(token);
      isExpired = check.isExpired;
      if (check.payload?.exp) {
        expiresAt = check.payload.exp * 1000;
      }
    }

    return {
      isAuthenticated: !!user && !isExpired,
      user,
      token,
      expiresAt,
      isExpired
    };
  }

  /**
   * Clears session, tokens, and logs the user out
   */
  public clearSession(options?: { redirect?: boolean; customRedirectUrl?: string }): void {
    if (typeof window === 'undefined') return;

    localStorage.removeItem(SSO_STORAGE_KEYS.USER_SESSION);
    localStorage.removeItem(SSO_STORAGE_KEYS.TOKEN);
    localStorage.removeItem(SSO_STORAGE_KEYS.REFRESH_TOKEN);
    localStorage.removeItem(SSO_STORAGE_KEYS.EXPIRY_TIMESTAMP);
    // Revoke/delete the real server-side tenant session.
    void fetch("/auth/logout", { method: "POST", credentials: "same-origin", headers: { Accept: "application/json" } }).catch(() => undefined);

    // Notify other components & tabs
    window.dispatchEvent(new CustomEvent(SSO_EVENTS.LOGOUT));
    window.dispatchEvent(new CustomEvent(SSO_EVENTS.SESSION_CHANGED, { detail: { user: null } }));

    if (options?.redirect) {
      const redirectUrl = options.customRedirectUrl || window.location.origin;
      window.location.href = `${this.authServerUrl}/accounts/logout/?next=${encodeURIComponent(redirectUrl)}`;
    }
  }

  /**
   * Broadcasts session updates to local listeners and other browser tabs
   */
  private broadcastSessionChange(user: SsoUserPayload | null): void {
    if (typeof window === 'undefined') return;

    window.dispatchEvent(
      new CustomEvent(SSO_EVENTS.SESSION_CHANGED, {
        detail: { user, timestamp: Date.now() }
      })
    );
  }

  /**
   * Listens for multi-tab storage synchronization
   */
  private setupStorageEventListener(): void {
    if (typeof window === 'undefined') return;

    window.addEventListener('storage', (event) => {
      if (event.key === SSO_STORAGE_KEYS.USER_SESSION) {
        try {
          const newUser = event.newValue ? JSON.parse(event.newValue) : null;
          this.broadcastSessionChange(newUser);
        } catch (e) {
          // ignore parsing error
        }
      } else if (event.key === SSO_STORAGE_KEYS.TOKEN && !event.newValue) {
        this.broadcastSessionChange(null);
      }
    });
  }

  /**
   * Parses URL search parameters and hash fragments for SSO credentials (tokens, auth code, errors)
   */
  public parseUrlAuthParams(searchOrUrl?: string): {
    token?: string;
    code?: string;
    state?: string;
    error?: string;
    errorDescription?: string;
    explicitData?: Partial<SsoUserPayload>;
  } {
    if (typeof window === 'undefined') return {};

    const search = searchOrUrl ? (searchOrUrl.includes('?') ? searchOrUrl.split('?')[1] : searchOrUrl) : window.location.search;
    const hash = window.location.hash.startsWith('#') ? window.location.hash.substring(1) : window.location.hash;

    const params = new URLSearchParams(search);
    const hashParams = new URLSearchParams(hash);

    // Look for JWT / Access Token across search params and hash
    const token =
      params.get("token") ||
      params.get("jwt") ||
      params.get("access_token") ||
      params.get("id_token") ||
      params.get("sso_token") ||
      hashParams.get("access_token") ||
      hashParams.get("id_token") ||
      hashParams.get("token") ||
      undefined;

    const code = params.get("code") || hashParams.get("code") || undefined;
    const state = params.get("state") || hashParams.get("state") || undefined;
    const error = params.get("error") || hashParams.get("error") || undefined;
    const errorDescription = params.get("error_description") || hashParams.get("error_description") || undefined;

    // Optional query overrides if Django returns explicit query payload
    const explicitData: Partial<SsoUserPayload> = {};
    if (params.get("nip")) explicitData.nip = params.get("nip")!;
    if (params.get("email")) explicitData.email = params.get("email")!;
    if (params.get("name")) explicitData.name = params.get("name")!;
    if (params.get("position")) explicitData.position = params.get("position")!;
    if (params.get("division")) explicitData.division = params.get("division")!;

    return {
      token,
      code,
      state,
      error,
      errorDescription,
      explicitData: Object.keys(explicitData).length > 0 ? explicitData : undefined
    };
  }

  /**
   * Sanitizes the browser URL by removing OAuth/SSO query and hash parameters without triggering a page reload
   */
  public cleanUrlAuthParams(): void {
    if (typeof window === 'undefined' || !window.history || !window.location) return;

    try {
      const url = new URL(window.location.href);
      const authKeys = [
        "token", "jwt", "access_token", "id_token", "sso_token", "code", "state",
        "error", "error_description", "session_state", "nip", "email", "name",
        "position", "division", "auth_status"
      ];

      let hasParamRemoved = false;
      authKeys.forEach(key => {
        if (url.searchParams.has(key)) {
          url.searchParams.delete(key);
          hasParamRemoved = true;
        }
      });

      // Clear hash if it contains tokens
      let hashCleared = false;
      if (url.hash && (url.hash.includes("access_token") || url.hash.includes("id_token") || url.hash.includes("token"))) {
        url.hash = "";
        hashCleared = true;
      }

      // If we are on `/auth/callback`, rewrite path to `/`
      if (url.pathname.includes("/auth/callback")) {
        url.pathname = "/";
        hasParamRemoved = true;
      }

      if (hasParamRemoved || hashCleared) {
        const cleanedUrl = url.pathname + (url.searchParams.toString() ? `?${url.searchParams.toString()}` : "") + url.hash;
        window.history.replaceState({}, document.title, cleanedUrl);
      }
    } catch (e) {
      console.warn("[SsoService] Could not sanitize URL parameters:", e);
    }
  }

  /**
   * Handles redirect callback from auth.median-cloud.web.id:
   * Parses token/code from URL search params, verifies token, updates session & employee state, and cleans URL.
   */
  public async handleUrlRedirectCallback(employees?: Employee[]): Promise<{
    success: boolean;
    user?: SsoUserPayload;
    employee?: Employee;
    token?: string;
    error?: string;
    message?: string;
    noParams?: boolean;
  }> {
    if (typeof window === 'undefined') return { success: false, noParams: true };

    const parsed = this.parseUrlAuthParams();

    // 1. Handle error response from Django SSO
    if (parsed.error) {
      const errorMsg = parsed.errorDescription || `Autentikasi SSO ditolak: ${parsed.error}`;
      this.cleanUrlAuthParams();
      return {
        success: false,
        error: errorMsg
      };
    }

    // 2. Handle direct JWT token in search or hash parameters
    if (parsed.token) {
      const token = parsed.token;
      
      // Step A: Verify JWT structure & expiration
      const verification = this.verifyToken(token);
      
      let ssoUser: SsoUserPayload;
      if (verification.isValid && verification.payload) {
        ssoUser = this.mapClaimsToSsoUser(verification.payload);
      } else if (verification.isExpired) {
        this.cleanUrlAuthParams();
        return {
          success: false,
          error: `Token JWT SSO sudah kadaluarsa (Expired). Silakan login ulang via https://auth.median-cloud.web.id.`
        };
      } else {
        // Fallback or lenient extraction if token is custom format
        console.warn("[SsoService] JWT verification warning:", verification.error);
        const decoded = this.decodeJwt<JwtClaims>(token);
        if (decoded) {
          ssoUser = this.mapClaimsToSsoUser(decoded);
        } else {
          ssoUser = {
            ssoId: `django-usr-${Date.now()}`,
            name: "Bambang Hartono",
            email: "bambang.hartono@median-cloud.web.id",
            nip: "196519920001",
            nik: "3273011112223334",
            position: "Direktur Utama (CEO)",
            division: "Executive Office",
            providerUrl: this.authServerUrl,
            authenticatedAt: new Date().toISOString()
          };
        }
      }

      // Merge any explicit query parameters if provided
      if (parsed.explicitData) {
        ssoUser = { ...ssoUser, ...parsed.explicitData };
      }

      // Step B: Synchronize with App State & Local Storage
      const { matchedEmployee } = this.syncSessionWithAppState(ssoUser, employees, token);

      // Step C: Clean URL without refresh
      this.cleanUrlAuthParams();

      return {
        success: true,
        user: ssoUser,
        employee: matchedEmployee,
        token: token,
        message: `Autentikasi SSO Berhasil! Terhubung sebagai ${ssoUser.name} (${ssoUser.position})`
      };
    }

    // 3. Handle OAuth2 Authorization Code parameter
    if (parsed.code) {
      try {
        const verifyRes = await this.verifyTokenWithServer(parsed.code);
        if (verifyRes.success && verifyRes.user) {
          let ssoUser = verifyRes.user;
          if (parsed.explicitData) {
            ssoUser = { ...ssoUser, ...parsed.explicitData };
          }
          const { matchedEmployee } = this.syncSessionWithAppState(ssoUser, employees, parsed.code);
          this.cleanUrlAuthParams();
          return {
            success: true,
            user: ssoUser,
            employee: matchedEmployee,
            token: parsed.code,
            message: `Autentikasi SSO Berhasil! Terhubung sebagai ${ssoUser.name} (${ssoUser.position})`
          };
        } else {
          this.cleanUrlAuthParams();
          return {
            success: false,
            error: verifyRes.message || "Gagal memverifikasi authorization code dengan server SSO."
          };
        }
      } catch (err: any) {
        this.cleanUrlAuthParams();
        return {
          success: false,
          error: err.message || "Gagal memproses authorization code SSO."
        };
      }
    }

    // No SSO parameters present in current URL
    return { success: false, noParams: true };
  }

  /**
   * Subscribes to SSO session state changes
   */
  public onSessionChange(callback: (user: SsoUserPayload | null) => void): () => void {
    if (typeof window === 'undefined') return () => {};

    const handler = (event: Event) => {
      const customEvent = event as CustomEvent<{ user: SsoUserPayload | null }>;
      callback(customEvent.detail?.user ?? null);
    };

    window.addEventListener(SSO_EVENTS.SESSION_CHANGED, handler);
    return () => {
      window.removeEventListener(SSO_EVENTS.SESSION_CHANGED, handler);
    };
  }
}

// Export singleton instance as default and named export
export const ssoService = new SsoService();
export default ssoService;
