// forked from https://github.com/joonhocho/superwild

class Matcher {
  private wchar;
  private pattern;
  private segments = [];
  private starCount = 0;
  private minLength = 0;
  private maxLength = 0;
  private segStartIndex = 0;

  constructor(pattern: string, wchar: string = "*") {
    this.wchar = wchar;
    this.pattern = pattern;

    for (let i = 0, len = pattern.length; i < len; i += 1) {
      const char = pattern[i];
      if (char === wchar) {
        this.starCount += 1;
        if (i > this.segStartIndex) {
          this.segments.push(pattern.substring(this.segStartIndex, i));
        }
        this.segments.push(char);
        this.segStartIndex = i + 1;
      }
    }

    if (this.segStartIndex < pattern.length) {
      this.segments.push(pattern.substring(this.segStartIndex));
    }

    if (this.starCount) {
      this.minLength = pattern.length - this.starCount;
      this.maxLength = Infinity;
    } else {
      this.maxLength = this.minLength = pattern.length;
    }
  }

  match(match: string): boolean {
    if (this.pattern === this.wchar) {
      return true;
    }
    if (this.segments.length === 0) {
      return this.pattern === match;
    }
    const { length } = match;
    if (length < this.minLength || length > this.maxLength) {
      return false;
    }

    let segLeftIndex = 0;
    let segRightIndex = this.segments.length - 1;
    let rightPos = match.length - 1;
    let rightIsStar = false;

    while (true) {
      const segment = this.segments[segRightIndex];
      segRightIndex -= 1;
      if (segment === this.wchar) {
        rightIsStar = true;
      } else {
        const lastIndex = rightPos + 1 - segment.length;
        const index = match.lastIndexOf(segment, lastIndex);
        if (index === -1 || index > lastIndex) {
          return false;
        }
        if (rightIsStar) {
          rightPos = index - 1;
          rightIsStar = false;
        } else {
          if (index !== lastIndex) {
            return false;
          }
          rightPos -= segment.length;
        }
      }
      if (segLeftIndex > segRightIndex) {
        break;
      }
    }
    return true;
  }
}

export default Matcher;
const segments = [];
export function Match(pattern: string, match: string, wchar: string = "*") {
  if (pattern === wchar) {
    return true;
  }
  segments.length = 0;
  let starCount = 0;
  let minLength = 0;
  let maxLength = 0;
  let segStartIndex = 0;
  for (let i = 0, len = pattern.length; i < len; i += 1) {
    const char = pattern[i];
    if (char === wchar) {
      starCount += 1;
      if (i > segStartIndex) {
        segments.push(pattern.substring(segStartIndex, i));
      }
      segments.push(char);
      segStartIndex = i + 1;
    }
  }

  if (segStartIndex < pattern.length) {
    segments.push(pattern.substring(segStartIndex));
  }

  if (starCount) {
    minLength = pattern.length - starCount;
    maxLength = Infinity;
  } else {
    maxLength = minLength = pattern.length;
  }

  if (segments.length === 0) {
    return pattern === match;
  }
  const length = match.length;
  if (length < minLength || length > maxLength) {
    return false;
  }

  let segLeftIndex = 0;
  let segRightIndex = segments.length - 1;
  let rightPos = match.length - 1;
  let rightIsStar = false;

  while (true) {
    const segment = segments[segRightIndex];
    segRightIndex -= 1;
    if (segment === wchar) {
      rightIsStar = true;
    } else {
      const lastIndex = rightPos + 1 - segment.length;
      const index = match.lastIndexOf(segment, lastIndex);
      if (index === -1 || index > lastIndex) {
        return false;
      }
      if (rightIsStar) {
        rightPos = index - 1;
        rightIsStar = false;
      } else {
        if (index !== lastIndex) {
          return false;
        }
        rightPos -= segment.length;
      }
    }
    if (segLeftIndex > segRightIndex) {
      break;
    }
  }
  return true;
}
