import { FC, useCallback, useEffect, useState } from 'react'
import AnimatedPageContainer from '../AnimatedPageContainer';
import { TypeEditor } from './type-editor';
import { useObjectState, useObjectStateWrapper } from '../../hooks/useObjectState';
import { FieldTypes, Schema, Template, TypeType } from '../../types/schema';
import { useInput } from '../../hooks/useInput';
import { useRecoilState } from 'recoil';
import { SchemaEditAtom } from '../../recoil/atoms/schema';
import { GameSystemsService } from '../../services/game-systems';
import { SchemaViewer } from './schema-viewer';
import { TemplateEditor } from './template-editor';
import { Icon } from '../Icon';


export const SchemaBuilder: FC = () => {
  const [schema, setSchema] = useRecoilState(SchemaEditAtom);
  const { update: updateSchema } = useObjectStateWrapper<Schema>(schema, setSchema);

  const { value: typeName, bind: bindTypeName, reset: resetTypeName } = useInput('');

  const [pageNumber, setPageNumber] = useState(0);

  const [lastSaved, setLastSaved] = useState(schema);

  const fetchSchema = useCallback(async () => {
    const result = await GameSystemsService.getSchema('286f4c18-d280-444b-8d7e-9a3dd09f64ef')
    if (result.status !== 200) return;
    const fetchedSchema = await result.json();
    // if (fetchedSchema.name === schema.name) return;
    if (!fetchedSchema.templates) fetchedSchema.templates = {}
    setSchema(fetchedSchema);
    setLastSaved(fetchedSchema);
  }, [setSchema])

  useEffect(() => {
    fetchSchema();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const [selectedType, setSelectedType] = useState('');

  const saveType = useCallback((name: string, type: TypeType) => {
    updateSchema(e => ({
      types: {
        ...e.types,
        [name]: type
      }
    }));
    resetTypeName();
    setPageNumber(0);
    setSelectedType('');
  }, [resetTypeName, updateSchema]);

  const saveSchema = useCallback(() => {
    GameSystemsService.saveSchema(schema);
    setLastSaved(schema);
  }, [schema])

  const selectTypeForEdit = useCallback((typeKey: string) => {
    setSelectedType(typeKey);
    setPageNumber(1);
  }, [])

  const { value: templateName, bind: bindTemplateName, reset: resetTemplateName } = useInput('', { disallowSpaces: true });
  const addTemplate = useCallback(() => {
    updateSchema(s => ({
      templates: {
        ...s.templates,
        [templateName]: {
          publishable: false,
          type: FieldTypes.any
        }
      }
    }));
    resetTemplateName();
  }, [resetTemplateName, templateName, updateSchema])

  const updateTemplate = useCallback((key: string, template: Template) => {
    updateSchema(s => ({
      templates: {
        ...s.templates,
        [key]: template
      }
    }))
  }, [updateSchema])

  const deleteType = useCallback((key: string) => {
    updateSchema(s => {
      const types = { ...s.types };
      delete types[key];
      return { types }
    })
  }, [updateSchema])

  return (
    <div className="container flex gap-4 p-8">
      <div className="panel w-2/3 h-full flex flex-col gap-4">
        <div>
          <p className="subheader mb-2">Add a template</p>
          <div className="mb-2">
            <input type="text" {...bindTemplateName} />
            <button onClick={addTemplate} disabled={!templateName}>Add</button>
          </div>
          <ul className="rounded-lg overflow-hidden">
            {Object.entries(schema.templates).map(([templateKey, template]) => (
              <TemplateEditor templateKey={templateKey} template={template} update={updateTemplate} />
            ))}
          </ul>
        </div>
        <hr />
        <div>
          <AnimatedPageContainer currentPage={pageNumber}>
            <div>
              <p className="subheader mb-2">Add a type</p>
              <input type="text" {...bindTypeName} />
              <button className="interactive" disabled={!typeName} onClick={() => setPageNumber(1)}>Configure</button>
            </div>
            <TypeEditor name={selectedType || typeName} saveType={saveType} type={selectedType ? schema.types[selectedType as keyof typeof schema.types] : undefined} />
          </AnimatedPageContainer>
          <ul className="mt-3 w-96">
            {Object.keys(schema.types).map(t => (
              <li className="odd:bg-black/50 flex justify-between p-2">
                {t}
                <div className="flex gap-3">
                  <button title="Edit" className="no-default" onClick={() => selectTypeForEdit(t)}>
                    <Icon icon="anvil" className="anvil svg-olive-drab hover:svg-olive-drab-100 w-6 h-6" />
                  </button>
                  <button title="Delete" className="no-default" onClick={() => deleteType(t)}>
                    <Icon icon="trash" className="trash-can svg-red-700 hover:svg-red-500 w-6 h-6" />
                  </button>
                </div>
              </li>
            ))}
          </ul>
        </div>
      </div>
      <div className="panel basis-1/3">
        <SchemaViewer schema={schema} onTypeClick={selectTypeForEdit} />
        <div className="flex gap-2 mt-2">
          <button
            onClick={saveSchema}
            disabled={lastSaved === schema}
          >
            Save Schema
          </button>
          <button
            className="bg-red-800"
            onClick={() => setSchema(lastSaved)}
            disabled={lastSaved === schema}
          >
            Discard Changes
          </button>
        </div>
      </div>
    </div>
  )
}