import { isProjectCodeTextPath, isLearnitiveEditableTextPath } from '@learnitive/project-storage';
import type { AppRouteInfo } from '@learnitive/types';
import { WsPath } from '@learnitive/ws-path';

export type SearchRecord = Record<string, string | null>;

/**
 * Convert search parameters to a URL search string
 */
export function toSearchString(search: SearchRecord): string {
  const params = new URLSearchParams();
  for (const [k, v] of Object.entries(search)) {
    if (v != null) {
      params.set(k, v);
    }
  }
  return params.toString();
}

/**
 * Parse URL search string into a record
 */
export function parseBrowserSearch(rawSearch: string): SearchRecord {
  const params = new URLSearchParams(rawSearch);
  const search: SearchRecord = {};
  for (const [key, value] of params) {
    search[key] = value;
  }
  return search;
}

/**
 * Strip base path from pathname
 */
export function stripBasePath(pathname: string, basePath: string): string {
  if (!basePath) return pathname;

  // Ensure basePath starts with / and has no trailing slash
  let normalizedBase = basePath.startsWith('/') ? basePath : `/${basePath}`;
  normalizedBase = normalizedBase.endsWith('/')
    ? normalizedBase.slice(0, -1)
    : normalizedBase;

  // Normalize path to remove trailing slash
  const normalizedPath = pathname.endsWith('/')
    ? pathname.slice(0, -1)
    : pathname;

  if (normalizedPath === normalizedBase) return '/';
  if (normalizedPath.startsWith(`${normalizedBase}/`))
    return normalizedPath.slice(normalizedBase.length);

  return normalizedPath;
}

/**
 * Join multiple path segments
 */
export function joinPaths(...parts: string[]): string {
  return `/${parts
    .map((p) => p.replace(/^\/|\/$/g, ''))
    .filter(Boolean)
    .join('/')}`.replace(/\/+/g, '/');
}

/**
 * Common route handling logic shared between strategies
 */
export function handleRouteInfo(
  route: string | undefined | null,
  params: SearchRecord,
): AppRouteInfo {
  if (!route) {
    return { route: 'welcome', payload: {} };
  }

  switch (route) {
    case 'editor': {
      const wsPath = params.wsPath?.trim() || '';
      const check = WsPath.safeParseFile(wsPath);
      if (
        !check.ok ||
        !check.data ||
        (!check.data.isMarkdown() &&
          !isLearnitiveEditableTextPath(check.data.path) &&
          !isProjectCodeTextPath(check.data.path))
      ) {
        return { route: 'not-found', payload: { path: '/invalid-wsPath' } };
      }
      return {
        route: 'editor',
        payload: { wsPath },
      };
    }

    case 'asset': {
      const wsPath = params.wsPath?.trim() || '';
      const check = WsPath.safeParseFile(wsPath);
      if (!check.ok) {
        return { route: 'not-found', payload: { path: '/invalid-wsPath' } };
      }
      return {
        route: 'asset',
        payload: { wsPath },
      };
    }

    case 'ws-home': {
      const wsName = params.wsName || '';
      const result = WsPath.validation.validateWsName(wsName);
      if (!result.ok) {
        return { route: 'not-found', payload: { path: '/invalid-wsName' } };
      }
      return {
        route: 'ws-home',
        payload: { wsName },
      };
    }

    case 'welcome': {
      return { route: 'welcome', payload: {} };
    }

    case 'not-found': {
      return {
        route: 'not-found',
        payload: { path: params.path ?? '' },
      };
    }

    case 'settings-general': {
      return {
        route: 'settings-general',
        payload: params.returnTo ? { returnTo: params.returnTo } : {},
      };
    }

    case 'settings-workspaces': {
      return {
        route: 'settings-workspaces',
        payload: params.returnTo ? { returnTo: params.returnTo } : {},
      };
    }

    case 'settings-recovery': {
      return {
        route: 'settings-recovery',
        payload: {
          ...(params.returnTo ? { returnTo: params.returnTo } : {}),
          ...(params.search ? { search: params.search } : {}),
        },
      };
    }

    default:
      return { route: 'not-found', payload: { path: route } };
  }
}

/**
 * Convert payload to search parameters
 */
export function payloadToSearch(
  route: string,
  payload: Record<string, unknown>,
): SearchRecord {
  const search: SearchRecord = { route };

  for (const [key, val] of Object.entries(payload)) {
    if (val == null) {
      continue;
    }
    search[key] = String(val);
  }

  return search;
}
