'use client';

import { Spell } from '@/api/spells.types';
import { levelText, rollDice } from '@/js/spells';
import { capitalize } from '@/js/utils';
import { Grid, Modal } from '@mantine/core';
import { notifications } from '@mantine/notifications';

interface SpellModalProps {
  spell: Spell;
  isOpen: boolean;
  onClose(): void;
}

export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps) {
  return (
    <Modal opened={isOpen} onClose={onClose} withCloseButton={false} size={'50%'} className='modal'>
      <h1 style={{ padding: '0', margin: '0' }}>{spell.name}</h1>
      <Grid gutter={1}>
        <Grid.Col span={4} style={{ paddingBottom: '1rem' }}>
          <span style={{ fontWeight: 'bold' }}>
            {capitalize(spell.school)} {levelText(spell)}
          </span>
        </Grid.Col>
        <Grid.Col span={8} style={{ paddingBottom: '1rem' }}>
          <div style={{ float: 'right' }}>
            <span style={{ float: 'right' }}>
              {spell.components.verbal && spell.components.somatic ? 'V, ' : 'V '}
              {spell.components.somatic && spell.components.material ? 'S, ' : 'S '}
              {spell.components.material && spell.components.materials_needed ? 'M*' : 'M'}
            </span>
            {spell.components.materials_needed && (
              <span style={{ fontSize: '0.8em', color: 'gray' }}>
                <br />*{capitalize(spell.components.materials_needed)}
              </span>
            )}
          </div>
        </Grid.Col>
        <Grid.Col span={6}>
          <span style={{ fontWeight: 'bold', paddingRight: '1em' }}>Sources:</span>
          {spell.sources.map((s) => (
            <span style={{ paddingRight: '0.6em' }}>
              {s.source}
              {s.page ? `.${s.page}` : ''}
            </span>
          ))}
        </Grid.Col>
        <Grid.Col span={6}>
          <span style={{ fontWeight: 'bold', marginRight: '1em' }}>Classes:</span>
          <span style={{ overflowWrap: 'break-word' }}>
            {spell.classes.map((c) => (
              <span style={{ paddingRight: '0.6em', display: 'inline-block' }} className='link'>
                {parseText(c, true)}
              </span>
            ))}
          </span>
        </Grid.Col>
        <Grid.Col span={6}>
          <span style={{ fontWeight: 'bold', paddingRight: '1em' }}>Casting Time:</span>
          <span style={{ paddingRight: '0.6em' }}>
            {spell.casting_time.value} {capitalize(spell.casting_time.unit)}
          </span>
        </Grid.Col>
        <Grid.Col span={6}>
          <span style={{ fontWeight: 'bold', paddingRight: '1em' }}>Range:</span>
          <span style={{ paddingRight: '0.6em' }}>
            {spell.range.type != 'point' && capitalize(spell.range.type)} {spell.range.value}{' '}
            {capitalize(spell.range.unit)}
          </span>
        </Grid.Col>
        <Grid.Col span={6}>
          <span style={{ fontWeight: 'bold', paddingRight: '1em' }}>Duration:</span>
          <span style={{ paddingRight: '0.6em' }}>
            {spell.durations.map((d) => (
              <span>
                {capitalize(d.type)} {d.value} {capitalize(d.unit)}
              </span>
            ))}
          </span>
        </Grid.Col>
        <Grid.Col span={12}>
          <SpellDescription spell={spell} />
        </Grid.Col>
      </Grid>
    </Modal>
  );
}

function parseText(text: string, capitalizeFirst?: boolean) {
  const regex = /{@(.*?) (.*?)}/g;
  const matches = text.matchAll(regex);
  const result = [];
  let lastIndex = 0;
  for (const match of matches) {
    const [full, type, name] = match;
    result.push(text.slice(lastIndex, match.index));
    if (match.index !== undefined) {
      if (type == 'dice') {
        result.push(
          <span onClick={() => handleLink(type, name)} className='link'>
            {name}
          </span>
        );
      } else if (type == 'scaledice') {
        // scaledice format is {@scaledice 1d6|1-9|1d6|}. Parse this out into dice, levels, and dice again.
        const [dice, levels] = name.split('|');
        result.push(
          <span onClick={() => handleLink('dice', dice)} className='link'>
            {dice}
          </span>
        );
      } else if (type == 'bold') {
        result.push(<span style={{ fontWeight: 'bold' }}>{name}</span>);
      } else if (type == 'subclass') {
        const [className, subclassName] = name.split('|');
        result.push(
          <span>
            {capitalize(className)} ({capitalize(subclassName)})
          </span>
        );
      } else {
        result.push(<span>{capitalizeFirst ? capitalize(name) : name}</span>);
      }
      lastIndex = match.index + full.length;
    }
  }
  result.push(text.slice(lastIndex));
  return result;
}

function handleLink(type: string, name: string) {
  if (type == 'spell') {
    console.log(`Link to spell: ${name}`);
  } else if (type == 'dice') {
    const rolls = rollDice(name);
    notifications.show({
      title: `Rolling ${name}`,
      message: `${rolls.join(' + ')} = ${rolls.reduce((a, b) => a + b, 0)}`,
      color: 'blue',
      autoClose: 5000,
      withCloseButton: false
    });
  } else if (type == 'scaledice') {
    console.log(`Link to scaledice: ${name}`);
  } else {
    console.error(`Unknown link type: ${type}`);
  }
}

function SpellDescription({ spell }: { spell: Spell }) {

  return (
    <>
      {spell.description && (
        <>
          {spell.description.entries.map((e) => (
            <>
              {e.text && <p>{parseText(e.text)}</p>}
              {e.list && (
                <ul>
                  {e.list.map((text) => (
                    <li>{parseText(text)}</li>
                  ))}
                </ul>
              )}
              {e.table && (
                <table>
                  <thead>
                    <tr>
                      {e.table.headers.map((label) => (
                        <th>{label}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {e.table.rows.map((row) => (
                      <tr>
                        {row.map((cell) => (
                          <td>{parseText(cell)}</td>
                        ))}
                      </tr>
                    ))}
                  </tbody>
                </table>
              )}
            </>
          ))}
        </>
      )}
    </>
  );
}
