import type { Criterion, Grade, Verdict } from './judging';
import type { Order } from './orders';
import { SPREADS } from '../sim/spreads';

/**
 * The judge. Deadpan, specific, never cruel about anything except MITEY, about
 * which he is unwell.
 *
 * Lines are keyed to the criterion that actually decided the score, so the
 * verdict always tells you the same thing the scorecard does — just meaner.
 */

type Bank = Record<string, { bad: string[]; good: string[] }>;

const BANK: Bank = {
  browning: {
    bad: [
      'I asked for {asked}. This is {got}. These are different words.',
      'You have made something adjacent to toast.',
      'The colour is a decision. You appear not to have made one.',
      'This is bread that has been near a toaster. Not the same thing.',
      'Somewhere in this kitchen is a dial. It has numbers on it.',
    ],
    good: [
      'The colour is correct. I want that on the record.',
      'That is the shade I asked for. Precisely the shade.',
      'Colour: no notes.',
    ],
  },
  evenness: {
    bad: [
      'One half of this has had a completely different morning to the other.',
      'It is striped. Toast should not be striped.',
      'I can see where you rescued it. So can everyone.',
      'This slice has weather.',
      'There are three separate climates on this toast.',
    ],
    good: [
      'Even, corner to corner. That is harder than it looks.',
      'No hot spots, no pale spots. Good.',
      'Uniform. Genuinely uniform.',
    ],
  },
  coverage: {
    bad: [
      'You have buttered an island and left a continent.',
      'The corners are not decorative. They are toast.',
      'There is a border of bare toast. Why is there a border.',
      'You got most of it. Most.',
      'A generous interpretation of the word "spread".',
    ],
    good: [
      'Edge to edge. Somebody was raised properly.',
      'Full coverage. Not a bare corner on it.',
      'You went to the crusts. I noticed.',
    ],
  },
  uniformity: {
    bad: [
      'It has a thick end and a thin end, like a bad argument.',
      'Lumpy. I can feel it from here.',
      'The {spread} is doing whatever it likes.',
      'This is not a film. It is terrain.',
    ],
    good: [
      'Flat, even, no ridges. Very tidy.',
      'Consistent all the way across.',
      'A properly level spread. Rare.',
    ],
  },
  char: {
    bad: [
      'I said no burnt bits. This is a burnt bit convention.',
      'There is carbon on this. Actual carbon.',
      'You burnt it. Then you served it. The second decision is the interesting one.',
      'I asked for toast, not evidence.',
    ],
    good: [
      'Not a scorch on it.',
      'No char. Well caught.',
      'Clean. Nothing burnt.',
    ],
  },
  integrity: {
    bad: [
      'You have not spread this. You have assaulted it.',
      'The surface is gone. You dragged it off and served the wound.',
      'Cold butter. Warm toast. One of these was your job.',
      'There is a crater. The coverage is admirable. The crater is not.',
      'This bread has been through something and would rather not discuss it.',
    ],
    good: [
      'Not a tear on it. That is the whole trick, and you did it.',
      'The surface is perfect. No drag, no gouges.',
      'Intact. You let something be warm first, didn\'t you.',
    ],
  },
  amount: {
    bad: [
      'I said {asked}. You have applied {got}.',
      'That is not {asked}. That is a statement.',
      'Somebody has never been told no.',
    ],
    good: [
      'Exactly the right amount. Exactly.',
      'The quantity is correct. Thank you.',
    ],
  },
  rind: {
    bad: [
      'All the {bits}, in one postcode.',
      'You have made a toast with a {bits} district.',
      'Every piece of {bits}, huddled together for warmth. Spread them OUT.',
      'One bite of this is all {bits}. The others are an apology.',
      'There is no {bits} on this. Did you eat it? You ate it.',
    ],
    good: [
      'Evenly strewn {bits}. That takes patience, and you had it.',
      'Every bite gets its {bits}. That is the entire craft.',
      'The {bits}: textbook distribution. I did not expect that today.',
    ],
  },
  consistency: {
    bad: [
      'It is weeping oil. I can hear it.',
      'You did not stir the jar. The jar knows. I know.',
      'This has the texture of grout. Grout with ambitions.',
      'Half slick, half plaster. Pick a toast.',
      'The oil went on first and the cement went on after. Stir. The. Jar.',
    ],
    good: [
      'Properly stirred. You can taste the difference, and I intend to.',
      'The consistency is exactly right. Someone respected the jar.',
      'Smooth, even, no slick. The jar was stirred by an adult.',
    ],
  },
  tool: {
    bad: [
      'You did this with a {tool}. I can tell. Everyone can tell.',
      'The {tool} was a choice.',
      'There was a whole drawer. You picked the {tool}.',
    ],
    good: [
      'Right tool. It shows.',
      'Correct utensil. Small thing. Not nothing.',
    ],
  },
};

/** MITEY gets its own vocabulary. */
const MITEY_CRIMES = [
  'This is not a scrape of MITEY. This is a hate crime.',
  'You have applied MITEY the way one applies paint.',
  'I asked to see the toast THROUGH it. I can see nothing. There is only night.',
  'That is a decade of MITEY on one slice. Some of us have to live here.',
];

const GRADE_OPENERS: Record<Grade, string[]> = {
  S: ['Well.', 'I have been doing this for thirty-one years.', 'Hm.'],
  A: ['Close.', 'Nearly.', 'Good.'],
  B: ['Adequate.', 'It is toast.', 'Fine.'],
  C: ['Hm.', 'Right.', 'Well, it exists.'],
  F: ['No.', 'Absolutely not.', 'Take it away.'],
};

const GRADE_CLOSERS: Record<Grade, string[]> = {
  S: [
    'That is the toast. Do it again tomorrow and I will start to worry.',
    'I have no notes. I dislike having no notes.',
    'Perfect. Irritatingly perfect.',
  ],
  A: ['Very nearly the toast.', 'One thing away from excellent.', 'Good work. Not finished work.'],
  B: ['It will be eaten. That is the bar it cleared.', 'Serviceable.', 'Nobody will complain. Nobody will remember.'],
  C: ['I have eaten worse. Not recently.', 'Try again.', 'This is why we have a scorecard.'],
  F: ['I am writing this down.', 'Start again. Properly.', 'The bread deserved better.'],
};

function fill(s: string, order: Order, v: Verdict, tool: string): string {
  const spread = SPREADS[order.spread];
  return s
    .replace('{asked}', order.amount === 'thin' ? 'a scrape' : order.amount)
    .replace('{got}', v.criteria.find((c) => c.key === 'amount')?.detail.split(' — ')[0] ?? 'that')
    // Mid-sentence, so lowercase — except MITEY, which is shouted on principle.
    .replace('{spread}', spread.id === 'mitey' ? 'MITEY' : spread.name.toLowerCase())
    .replaceAll('{bits}', spread.particles?.name ?? 'rind')
    .replace('{tool}', tool.toLowerCase());
}

/**
 * Two lines: what went worst, and what went best. Which is what the scorecard
 * says too — this just says it with feeling.
 */
export function verdictLines(v: Verdict, order: Order, tool: string, rand: () => number): string[] {
  const pick = <T>(a: T[]): T => a[Math.floor(rand() * a.length)];
  const out: string[] = [];
  out.push(pick(GRADE_OPENERS[v.grade]));

  const mitey = order.spread === 'mitey';
  const amountBad = (v.criteria.find((c) => c.key === 'amount')?.score ?? 1) < 0.4;
  if (mitey && amountBad) {
    out.push(pick(MITEY_CRIMES));
  } else if (v.worst.score < 0.72) {
    out.push(fill(pick(BANK[v.worst.key]?.bad ?? ['Hm.']), order, v, tool));
  }

  if (v.best.score > 0.85 && v.best.key !== v.worst.key) {
    out.push(fill(pick(BANK[v.best.key]?.good ?? []), order, v, tool));
  }

  out.push(pick(GRADE_CLOSERS[v.grade]));
  return out.filter(Boolean);
}

/** Which portrait to show. */
export function judgeFace(grade: Grade): string {
  switch (grade) {
    case 'S':
      return 'impressed';
    case 'A':
      return 'intrigued';
    case 'B':
      return 'neutral';
    case 'C':
      return 'disappointed';
    default:
      return 'horrified';
  }
}

export function describeCriterion(c: Criterion): string {
  return c.detail;
}
