import { parseDocument } from 'yaml';

export interface SkillMarkdownParts {
  body: string;
  bodyPrefix: string;
  frontmatter: string;
  hasFrontmatter: boolean;
  lineEnding: '\n' | '\r\n';
}

// The closing marker is accepted only when `---` occupies the complete line.
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(\r?\n|$)/;

export function splitSkillMarkdown(source: string): SkillMarkdownParts {
  const lineEnding = source.includes('\r\n') ? '\r\n' : '\n';
  const match = FRONTMATTER_PATTERN.exec(source);
  if (!match) {
    return {
      body: source,
      bodyPrefix: '',
      frontmatter: '',
      hasFrontmatter: false,
      lineEnding,
    };
  }
  return {
    body: source.slice(match[0].length),
    bodyPrefix: match[2] || '',
    frontmatter: match[1] || '',
    hasFrontmatter: true,
    lineEnding,
  };
}

export function joinSkillMarkdown(parts: SkillMarkdownParts): string {
  if (!parts.hasFrontmatter) return parts.body;
  return `---${parts.lineEnding}${parts.frontmatter}${parts.lineEnding}---${parts.bodyPrefix}${parts.body}`;
}

export function updateFrontmatterScalar(
  frontmatter: string,
  key: 'description' | 'name',
  value: string,
  lineEnding: '\n' | '\r\n' = '\n',
): string {
  const serialized = JSON.stringify(value.trim());
  const fieldPattern = new RegExp(`^${key}\\s*:[^\\r\\n]*$`, 'm');
  const match = fieldPattern.exec(frontmatter);
  const current = match?.[0];
  if (current) {
    const raw = current.slice(current.indexOf(':') + 1).trim();
    const following = frontmatter.slice((match?.index || 0) + current.length);
    const hasIndentedContinuation = /^\r?\n[ \t]+\S/.test(following);
    const unsafeScalar =
      !raw ||
      /^[>|]/.test(raw) ||
      /\s+#/.test(raw) ||
      /^[{[&*!]/.test(raw) ||
      /^(?:null|true|false|[-+]?\d+(?:\.\d+)?)$/i.test(raw) ||
      hasIndentedContinuation;
    if (unsafeScalar) {
      throw new Error(`${key} 使用复杂 YAML，请在源码模式中编辑`);
    }
    return frontmatter.replace(fieldPattern, `${key}: ${serialized}`);
  }
  const suffix =
    frontmatter && !frontmatter.endsWith(lineEnding) ? lineEnding : '';
  return `${frontmatter}${suffix}${key}: ${serialized}`;
}

export function syncSkillMarkdownFrontmatter(
  source: string,
  name: string,
  description: string,
): string {
  const parts = splitSkillMarkdown(source);
  if (!parts.hasFrontmatter) {
    parts.hasFrontmatter = true;
    parts.bodyPrefix = `${parts.lineEnding}${parts.lineEnding}`;
  }
  if (readFrontmatterScalar(parts.frontmatter, 'name').trim() !== name.trim()) {
    parts.frontmatter = updateFrontmatterScalar(
      parts.frontmatter,
      'name',
      name,
      parts.lineEnding,
    );
  }
  if (
    readFrontmatterScalar(parts.frontmatter, 'description').trim() !==
    description.trim()
  ) {
    parts.frontmatter = updateFrontmatterScalar(
      parts.frontmatter,
      'description',
      description,
      parts.lineEnding,
    );
  }
  return joinSkillMarkdown(parts);
}

export function readFrontmatterScalar(
  frontmatter: string,
  key: 'description' | 'name',
): string {
  if (!frontmatter.trim()) return '';
  try {
    const document = parseDocument(frontmatter, {
      prettyErrors: false,
      schema: 'failsafe',
      strict: true,
      uniqueKeys: true,
    });
    if (document.errors.length > 0) return '';
    const value = document.get(key);
    return typeof value === 'string' ? value : '';
  } catch {
    return '';
  }
}

export function normalizeSkillRelativeLink(href: string): string {
  if (hasUnsafeUriForm(href)) return '';
  return href.split('#', 1)[0]?.replace(/^\.\//, '') || '';
}

export function resolveSkillRelativePath(
  currentPath: string,
  href: string,
): string | undefined {
  const cleanHref = href.split(/[?#]/, 1)[0] || '';
  if (
    !cleanHref ||
    hasUnsafeUriForm(href) ||
    cleanHref.startsWith('/') ||
    cleanHref.includes('\\')
  )
    return undefined;
  const segments = currentPath.split('/');
  segments.pop();
  for (const segment of cleanHref.split('/')) {
    if (!segment || segment === '.') continue;
    if (segment === '..') {
      if (segments.length === 0) return undefined;
      segments.pop();
    } else {
      segments.push(segment);
    }
  }
  return segments.join('/');
}

function hasUnsafeUriForm(value: string) {
  const href = value.trim();
  return (
    !href ||
    /^[a-z][a-z\d+.-]*:/i.test(href) ||
    href.startsWith('//') ||
    [...href].some((character) => {
      const code = character.codePointAt(0) || 0;
      return code < 32 || code === 127;
    })
  );
}
