"use client";

import { FC, useCallback, useEffect, useState } from "react";
import AnimatedPageContainer from "@/components/AnimatedPageContainer";
import { TypeEditor } from "./type-editor";
import { useObjectStateWrapper } from "@/hooks/useObjectState";
import { useInput } from "../../hooks/useInput";
import { useRecoilState } from "recoil";
import { SchemaEditAtom } from "@/recoil/atoms/schema";
import { SchemaViewer } from "./schema-viewer";
import { TemplateEditor } from "./template-editor";
import { Icon } from "@/components/Icon";
import { useParams } from "next/navigation";
import { FieldTypes } from "./fieldtypes";
import { findSchema, saveSchemaDb } from "@/actions/Schemas/index";
import { useToast } from "../toast";

export const SchemaBuilder: FC = () => {
  const [schema, setSchema] = useRecoilState(SchemaEditAtom);
  // const resetSchema = useResetRecoilState(SchemaEditAtom);
  const { createToast } = useToast();
  const { update: updateSchema, bindProperty: bindSchemaProperty } =
    useObjectStateWrapper<Schema>(schema, setSchema);

  const { schemaId, id: gameSystemId } = useParams<{
    schemaId: string;
    id: string;
  }>();

  useEffect(() => {
    if (schemaId !== "create" && schemaId !== schema.id)
      findSchema(schemaId).then((sc) => {
        if (!sc) return;
        setSchema(sc);
      });
  }, [schema.id, schemaId, setSchema]);

  useEffect(() => {
    if (gameSystemId && !schema.gameSystemId)
      setSchema((sc) => ({ ...sc, gameSystemId }));
  }, [gameSystemId, schema.gameSystemId, setSchema]);

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

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

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

  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(async () => {
    createToast({ msg: "Saving Schema", fading: true });
    await saveSchemaDb(schema);
  }, [createToast, schema]);

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

  const {
    value: schemaFieldName,
    bind: bindSchemaFieldName,
    reset: resetSchemaFieldName,
  } = useInput("", { disallowSpaces: true });
  const addSchemaField = useCallback(() => {
    updateSchema((s) => ({
      schema: {
        ...s.schema,
        [schemaFieldName]: FieldTypes.any,
      },
    }));
    resetSchemaFieldName();
  }, [resetSchemaFieldName, schemaFieldName, updateSchema]);

  const updateSchemaField = useCallback(
    (key: string, template: Template) => {
      updateSchema((s) => ({
        schema: {
          ...s.schema,
          [key]: template,
        },
      }));
    },
    [updateSchema],
  );

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

  return (
    <div className="flex gap-4 p-8">
      <div className="panel w-2/3 h-full flex flex-col gap-4">
        <div>
          <input
            type="text"
            {...bindSchemaProperty("name")}
            placeholder="Schema Name"
          />
        </div>
        <div>
          <p className="subheader mb-2">Add Schema Field</p>
          <div className="mb-2">
            <input type="text" {...bindSchemaFieldName} />
            <button onClick={addSchemaField} disabled={!schemaFieldName}>
              Add
            </button>
          </div>
          <ul className="rounded-lg overflow-hidden">
            {Object.entries(schema.schema).map(
              ([schemaFieldKey, schemaField]) => (
                <TemplateEditor
                  key={schemaFieldKey}
                  templateKey={schemaFieldKey}
                  template={schemaField}
                  update={updateSchemaField}
                />
              ),
            )}
          </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
                key={"type" + t}
                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">
        <div className="flex gap-2 mb-2">
          <button
            className="btn btn-small bg-green-800"
            onClick={saveSchema}
            disabled={lastSaved === schema}
          >
            Save Schema
          </button>
          <button
            className="bg-red-800 btn btn-small"
            onClick={() => setSchema(lastSaved)}
            disabled={lastSaved === schema}
          >
            Discard Changes
          </button>
        </div>
        <SchemaViewer schema={schema} onTypeClick={selectTypeForEdit} />
      </div>
    </div>
  );
};
