import { Injectable } from '@nestjs/common';
import { RedmineTypes } from '../models/redmine-types';
import { IssueEnhancerInterface } from './issue-enhancer-interface';

export type StyleRule = {
  default?: boolean;
  priorityName?: string;
  style?: string;
  className?: string;
};

export const defaultRule: StyleRule = {
  default: true,
  style: 'background-color: gray; color: white;',
};

export const defaultKey = 'priorityStyle';

export function ValidateStyleRule(rule: StyleRule): boolean {
  return (
    // check default prop
    (typeof rule.default === 'boolean' ||
      typeof rule.default === 'undefined') &&
    // check priority name prop
    (rule.default ||
      (!rule.default &&
        typeof rule.priorityName === 'string' &&
        rule.priorityName.length > 0)) &&
    // check style or className props
    ((typeof rule.style === 'string' && rule.style.length > 0) ||
      (typeof rule.className === 'string' && rule.className.length > 0))
  );
}

export function HasDefaultRule(rules: StyleRule[]): boolean {
  const hasDefaultRule = rules.find((rule) => rule.default);
  return Boolean(hasDefaultRule);
}

@Injectable()
export class PriorityStylesEnhancer implements IssueEnhancerInterface {
  name: string;

  private rules: StyleRule[];

  private targetKey: string;

  constructor(rules?: StyleRule[], targetKey?: string) {
    let validatedRules: StyleRule[] = [];
    if (rules && rules.length > 0) {
      validatedRules = rules.filter(ValidateStyleRule);
    }
    if (!HasDefaultRule(validatedRules)) {
      validatedRules.push(defaultRule);
    }
    this.rules = validatedRules;

    this.targetKey =
      typeof targetKey === 'string' && targetKey.length > 0
        ? targetKey
        : defaultKey;
  }

  async enhance(
    issue: RedmineTypes.ExtendedIssue,
  ): Promise<RedmineTypes.ExtendedIssue> {
    const priorityName = issue?.priority?.name;
    if (!priorityName) return issue;
    const priorityRule = this.findPriorityRule(priorityName);
    issue[this.targetKey] = priorityRule.style || priorityRule.className;
    return issue;
  }

  private findPriorityRule(priority: string): StyleRule {
    return (this.rules.find((r) => r.priorityName === priority) ||
      this.rules.find((r) => r.default)) as StyleRule;
  }
}

export type PrioritiesStyleParams = {
  rules: StyleRule[];
  targetKey: string;
};

export type ConfigWithPriorityStyles = {
  priorities?: PrioritiesStyleParams;
  [key: string]: any;
};

export function CreatePriorityStylesEnhancer(
  cfg: ConfigWithPriorityStyles,
): PriorityStylesEnhancer {
  let params: PrioritiesStyleParams;
  if (cfg.priorities && cfg.priorities.rules && cfg.priorities.targetKey) {
    params = cfg.priorities;
  } else {
    params = {
      rules: [defaultRule],
      targetKey: defaultKey,
    };
  }
  return new PriorityStylesEnhancer(params.rules, params.targetKey);
}
