import type { ContentExpectations, ExpectationResult, ValueExpectation } from "../../expect/types";
import type { DnsValuesExpectation } from "./types";

import { checkContentExpectations } from "../../expect/content";
import { mismatchFailure } from "../../expect/failure";
import { checkValueExpectation } from "../../expect/value";

export function checkAnswerCount(actual: number, matcher: ValueExpectation): ExpectationResult {
  return checkValueExpectation(actual, matcher, {
    message: "answer 数量不满足条件",
    path: "answerCount",
    phase: "answerCount",
  });
}

export function checkDnsValues(actualValues: string[], expectation: DnsValuesExpectation): ExpectationResult {
  const actualSet = new Set(actualValues);

  if (expectation.exact) {
    const expectedSet = new Set(expectation.exact);
    if (actualSet.size !== expectedSet.size || ![...expectedSet].every((v) => actualSet.has(v))) {
      return {
        failure: mismatchFailure(
          "values",
          "values",
          expectation.exact,
          actualValues,
          "values 集合不匹配（exact 忽略顺序）",
        ),
        matched: false,
      };
    }
  }

  if (expectation.include) {
    for (const v of expectation.include) {
      if (!actualSet.has(v)) {
        return {
          failure: mismatchFailure("values", "values", `包含 ${v}`, actualValues, `values 缺少期望值: ${v}`),
          matched: false,
        };
      }
    }
  }

  if (expectation.exclude) {
    for (const v of expectation.exclude) {
      if (actualSet.has(v)) {
        return {
          failure: mismatchFailure("values", "values", `排除 ${v}`, actualValues, `values 包含排除值: ${v}`),
          matched: false,
        };
      }
    }
  }

  return { failure: null, matched: true };
}

export function checkFlag(actual: boolean, expected: boolean | undefined, name: string): ExpectationResult | null {
  if (expected === undefined) return null;
  if (actual === expected) return { failure: null, matched: true };
  return {
    failure: mismatchFailure(name, name, expected, actual, `${name} 不匹配`),
    matched: false,
  };
}

export function checkRcode(actual: string, expected: string[]): ExpectationResult {
  if (expected.includes(actual)) return { failure: null, matched: true };
  return {
    failure: mismatchFailure("rcode", "rcode", expected.join(", "), actual, `RCODE 不在期望列表中`),
    matched: false,
  };
}

export function checkResponded(responded: boolean, expected: boolean): ExpectationResult {
  if (responded === expected) return { failure: null, matched: true };
  if (!responded && expected) {
    return {
      failure: mismatchFailure("responded", "responded", true, false, "期望收到响应但未收到"),
      matched: false,
    };
  }
  return {
    failure: mismatchFailure("responded", "responded", false, true, "期望无响应但收到响应"),
    matched: false,
  };
}

export function checkResult(
  observation: Record<string, unknown>,
  expectations: ContentExpectations,
): ExpectationResult {
  return checkContentExpectations(JSON.stringify(observation), expectations, { path: "result", phase: "result" });
}

export function checkTtlMax(actual: number, matcher: ValueExpectation): ExpectationResult {
  return checkValueExpectation(actual, matcher, {
    message: "最大 TTL 不满足条件",
    path: "ttlMax",
    phase: "ttlMax",
  });
}

export function checkTtlMin(actual: number, matcher: ValueExpectation): ExpectationResult {
  return checkValueExpectation(actual, matcher, {
    message: "最小 TTL 不满足条件",
    path: "ttlMin",
    phase: "ttlMin",
  });
}

export function checkValueCount(actual: number, matcher: ValueExpectation): ExpectationResult {
  return checkValueExpectation(actual, matcher, {
    message: "value 数量不满足条件",
    path: "valueCount",
    phase: "valueCount",
  });
}
