// 一致性语料:解析、序列化、变换与校验的单一事实来源。

///|
fn check(failures : Array[String], name : String, condition : Bool) -> Unit {
  if !condition {
    failures.push(name)
  }
}

///|
fn parse_srt_ok(text : String) -> Subtitle? {
  match parse_srt(text) {
    Ok(subtitle) => Some(subtitle)
    Err(_) => None
  }
}

///|
fn parse_vtt_ok(text : String) -> Subtitle? {
  match parse_vtt(text) {
    Ok(subtitle) => Some(subtitle)
    Err(_) => None
  }
}

///|
const SAMPLE_SRT : String = "1\n00:00:01,000 --> 00:00:04,000\nHello\n\n2\n00:00:05,000 --> 00:00:08,000\nWorld\n"

///|
const SAMPLE_VTT : String = "WEBVTT\n\n1\n00:00:01.000 --> 00:00:04.000\nHello\n\n2\n00:00:05.000 --> 00:00:08.000\nWorld\n"

///|
/// 一致性语料条数。
pub fn conformance_case_count() -> Int {
  17
}

///|
/// 运行一致性语料,返回失败描述(空数组表示全部通过)。
pub fn run_conformance() -> Array[String] {
  let failures : Array[String] = []
  let simple = "1\n00:00:01,000 --> 00:00:04,000\nHello\n"
  match parse_srt_ok(simple) {
    None => failures.push("parse-simple: 解析失败")
    Some(subtitle) => {
      check(failures, "parse-simple: 条数", subtitle.cues.length() == 1)
      check(failures, "parse-simple: 开始", subtitle.cues[0].start_ms == 1000)
      check(failures, "parse-simple: 结束", subtitle.cues[0].end_ms == 4000)
      check(failures, "parse-simple: 文本", subtitle.cues[0].text == "Hello")
    }
  }
  match parse_srt_ok(SAMPLE_SRT) {
    None => failures.push("parse-two: 解析失败")
    Some(subtitle) => {
      check(failures, "parse-two: 条数", subtitle.cues.length() == 2)
      check(
        failures,
        "parse-two: 第二条开始",
        subtitle.cues[1].start_ms == 5000,
      )
    }
  }
  let multiline = "1\n00:00:01,000 --> 00:00:04,000\nline one\nline two\n"
  match parse_srt_ok(multiline) {
    None => failures.push("parse-multiline: 解析失败")
    Some(subtitle) =>
      check(
        failures,
        "parse-multiline: 文本",
        subtitle.cues[0].text == "line one\nline two",
      )
  }
  match
    parse_srt_ok("\u{feff}1\r\n00:00:01,000 --> 00:00:04,000\r\nHello\r\n") {
    None => failures.push("parse-bom-crlf: 解析失败")
    Some(subtitle) =>
      check(
        failures,
        "parse-bom-crlf: 文本",
        subtitle.cues[0].text == "Hello",
      )
  }
  match parse_srt_ok(SAMPLE_SRT) {
    None => failures.push("roundtrip: 解析失败")
    Some(subtitle) => {
      let roundtrip = parse_srt_ok(serialize_srt(subtitle))
      match roundtrip {
        None => failures.push("roundtrip: 二次解析失败")
        Some(again) =>
          check(failures, "roundtrip: 条数", again.cues.length() == 2)
      }
    }
  }
  match parse_vtt_ok(SAMPLE_VTT) {
    None => failures.push("vtt-parse: 解析失败")
    Some(subtitle) =>
      check(failures, "vtt-parse: 条数", subtitle.cues.length() == 2)
  }
  match parse_vtt_ok(SAMPLE_VTT) {
    None => failures.push("vtt-serialize: 解析失败")
    Some(subtitle) => {
      let output = serialize_vtt(subtitle)
      check(failures, "vtt-serialize: 头", output.has_prefix("WEBVTT\n\n"))
      check(failures, "vtt-serialize: 点号", output.contains("00:00:01.000"))
    }
  }
  match parse_srt_ok(SAMPLE_SRT) {
    None => failures.push("shift: 解析失败")
    Some(subtitle) => {
      let moved = shift(subtitle, 1500)
      check(failures, "shift: 开始", moved.cues[0].start_ms == 2500)
      check(failures, "shift: 结束", moved.cues[0].end_ms == 5500)
    }
  }
  match parse_srt_ok(simple) {
    None => failures.push("shift-clamp: 解析失败")
    Some(subtitle) => {
      let moved = shift(subtitle, -5000)
      check(failures, "shift-clamp: 不为负", moved.cues[0].start_ms == 0)
    }
  }
  match parse_srt_ok(simple) {
    None => failures.push("scale: 解析失败")
    Some(subtitle) => {
      let scaled = scale(subtitle, 200)
      check(failures, "scale: 开始", scaled.cues[0].start_ms == 2000)
      check(failures, "scale: 结束", scaled.cues[0].end_ms == 8000)
    }
  }
  let overlap = "1\n00:00:01,000 --> 00:00:05,000\nA\n\n2\n00:00:04,000 --> 00:00:08,000\nB\n"
  match parse_srt_ok(overlap) {
    None => failures.push("validate-overlap: 解析失败")
    Some(subtitle) => {
      let issues = validate(subtitle, ValidateOptions::new())
      let mut found = false
      for issue in issues {
        if issue_kind_name(issue.kind) == "overlap" {
          found = true
        }
      }
      check(failures, "validate-overlap: 检出", found)
      let fixed = resolve_overlaps(subtitle, 100)
      let fixed_issues = validate(fixed, ValidateOptions::new())
      let mut still_overlap = false
      for issue in fixed_issues {
        if issue_kind_name(issue.kind) == "overlap" {
          still_overlap = true
        }
      }
      check(failures, "resolve-overlap: 已消除", !still_overlap)
    }
  }
  let empty = "1\n00:00:01,000 --> 00:00:04,000\n   \n"
  match parse_srt_ok(empty) {
    None => failures.push("validate-empty: 解析失败")
    Some(subtitle) => {
      let issues = validate(subtitle, ValidateOptions::new())
      let mut found = false
      for issue in issues {
        if issue_kind_name(issue.kind) == "empty-text" {
          found = true
        }
      }
      check(failures, "validate-empty: 检出", found)
    }
  }
  let short = "1\n00:00:01,000 --> 00:00:01,200\nA\n"
  match parse_srt_ok(short) {
    None => failures.push("validate-short: 解析失败")
    Some(subtitle) => {
      let issues = validate(subtitle, ValidateOptions::new())
      let mut found = false
      for issue in issues {
        if issue_kind_name(issue.kind) == "too-short" {
          found = true
        }
      }
      check(failures, "validate-short: 检出", found)
    }
  }
  let long_line = "1\n00:00:01,000 --> 00:00:05,000\n\{long_text()}\n"
  match parse_srt_ok(long_line) {
    None => failures.push("validate-long: 解析失败")
    Some(subtitle) => {
      let issues = validate(subtitle, ValidateOptions::new())
      let mut found = false
      for issue in issues {
        if issue_kind_name(issue.kind) == "line-too-long" {
          found = true
        }
      }
      check(failures, "validate-long: 检出", found)
    }
  }
  match parse_srt("1\nnot-a-timestamp\nHello\n") {
    Ok(_) => failures.push("invalid-timestamp: 不应解析成功")
    Err(_) => ()
  }
  match parse_srt_ok("1\n01:02:03,004 --> 01:02:04,005\nA\n") {
    None => failures.push("format: 解析失败")
    Some(subtitle) =>
      check(
        failures,
        "format: SRT 时间",
        serialize_srt(subtitle).contains("01:02:03,004"),
      )
  }
  match
    parse_vtt(
      "WEBVTT\n\nNOTE a comment\n\n1\n00:00:01.000 --> 00:00:04.000\nHello\n",
    ) {
    Err(_) => failures.push("vtt-note: 解析失败")
    Ok(subtitle) =>
      check(failures, "vtt-note: 跳过 NOTE", subtitle.cues.length() == 1)
  }
  failures
}

///|
fn long_text() -> String {
  let builder = StringBuilder()
  let mut i = 0
  while i < 60 {
    builder.write_string("x")
    i = i + 1
  }
  builder.to_string()
}