import { createForm } from '@felte/solid';
import { Component, Index, Match, onMount, Show, Switch } from 'solid-js';
import { TextField, Button } from '@kobalte/core';
import reporter from '@felte/reporter-tippy';
import './style.css';
import { useNavigate } from 'solid-start';
import { adminCredentials } from '../credentials';
import { put } from '~/lib/put';
import { del } from '~/lib/del';
import { isFunction } from 'lodash';
import { userId } from '~/lib/user-id';
import { userExists } from '~/lib/user-exists';

interface Props {
  values?: () => any;
}

const User: Component<Props> = (props) => {
  const navigate = useNavigate();

  const credentials = adminCredentials();
  const { database } = credentials || { database: null };

  const isNew = () => !isFunction(props?.values);

  const getValues = () => {
    if (isNew()) {
      return { database, subscriptions: [] };
    }
    return { subscriptions: [], ...props.values() };
  };

  const submitHandler = async (values: any, context: any) => {
    console.log({
      caller: 'User / submitHandler',
      props,
      values,
      context,
    });
    const id = getValues()?._id ?? userId(values.username, values.database);
    await put(id, values, isNew());
    const couchUserId = `org.couchdb.user:${values.username}`;
    const userDoc = {
      _id: couchUserId,
      name: values.username,
      password: values.password,
      type: 'user',
      roles: [],
    };
    await put(couchUserId, userDoc, isNew(), '_users');

    const subscriptions = !!props?.values
      ? props.values().subscriptions ?? []
      : [];
    const updatedSubscriptions = values.subscriptions ?? [];

    const isIn = (username: string, subs: any[]) => {
      for (let i = 0; i < subs.length; i++) {
        let sub = subs[i];
        if (username === sub.username) {
          return true;
        }
      }
      return false;
    };

    for (let i = 0; i < updatedSubscriptions.length; i++) {
      let subscription = updatedSubscriptions[i];
      if (!isIn(subscription.username, subscriptions)) {
        console.log({
          caller: 'User / submitHandler / new subscription',
          username: subscription.username,
        });
      }
    }

    for (let i = 0; i < subscriptions.length; i++) {
      let subscription = subscriptions[i];
      if (!isIn(subscription.username, updatedSubscriptions)) {
        console.log({
          caller: 'User / submitHandler / deleted subscription',
          username: subscription.username,
        });
      }
    }

    setInitialValues(values);
    setIsDirty(false);

    navigate(`/user/${id}`);
  };

  const cancelHandler = () => {
    navigate(`/user/`);
  };

  const deleteHandler = async () => {
    console.log({
      caller: 'User / deleteHandler',
      id: getValues()?._id,
      props,
    });
    await del(getValues()?._id);
    navigate(`/user/`);
  };

  const validationHandler = async (values: any) => {
    let errors: any = {};
    const credentials = adminCredentials();
    if (!credentials) {
      return errors;
    }
    const { database, username, password } = credentials;
    try {
      const response = await fetch(database, { mode: 'cors' });
      const dbStatus = await response.json();
      if (!dbStatus.couchdb) {
        errors.database = 'The URL is not a couchdb instance';
      }
    } catch (error) {
      errors.database = "Can't access the database";
    }
    if (!!errors.database) {
      return errors;
    }

    const subscriptions = values.subscriptions ?? [];

    for (let i = 0; i < subscriptions.length; i++) {
      let subscription = subscriptions[i];
      if (
        !!subscription.username &&
        !(await userExists(subscription.username))
      ) {
        if (!errors.subscriptions) {
          errors.subscriptions = [];
        }
        errors.subscriptions[i] = { username: "User doesn't exist" };
      }
    }

    if (isNew()) {
      if (await userExists(values.username)) {
        errors.username = 'The user is already existing';
      }
    }
    console.log({ caller: 'Users / validationHandler', values, errors });
    return errors;
  };

  const {
    form,
    data,
    setData,
    setIsDirty,
    setInitialValues,
    reset,
    addField,
    unsetField,
    isDirty,
    isValid,
  } = createForm({
    onSubmit: submitHandler,
    extend: reporter(),
    validate: validationHandler,
    initialValues: getValues(),
  });

  const createUserHandler = async () => {
    console.log({
      caller: 'User / createUserHandler',
      props,
      data: data(),
    });
    //    setOpenUserNamePasswordDialog(true);
  };

  const subscriptions = () => data('subscriptions');

  function removeSubscription(index: number) {
    return () => {
      unsetField(`subscriptions.${index}`);
      setIsDirty(true);
    };
  }

  function addSubscription(index?: number) {
    return () => {
      addField(`subscriptions`, { username: '', direction: '' }, index);
      setIsDirty(true);
    };
  }

  console.log({
    caller: 'User ',
    props,
    values: getValues(),
    data: data(),
  });

  return (
    <>
      <Show when={!isNew()}>
        <h2>{userId(data('username'), data('database'))}</h2>
      </Show>
      <form use:form>
        <TextField.Root>
          <TextField.Label>Mail address</TextField.Label>
          <TextField.Input
            type='mail'
            name='mail'
            required={true}
            placeholder='Email address'
          />
          <TextField.ErrorMessage>
            Please provide a valid URL
          </TextField.ErrorMessage>
        </TextField.Root>
        <TextField.Root>
          <TextField.Label>Database</TextField.Label>
          <TextField.Input
            type='url'
            name='database'
            required={true}
            placeholder='Database URL'
            readOnly={true}
          />
        </TextField.Root>
        <TextField.Root>
          <TextField.Label>User name</TextField.Label>
          <TextField.Input
            type='text'
            name='username'
            required={true}
            placeholder='user name'
            readOnly={!isNew()}
          />
        </TextField.Root>
        <TextField.Root>
          <TextField.Label>Password</TextField.Label>
          <TextField.Input
            type='text'
            name='password'
            required={true}
            placeholder='Password'
            autocomplete='off'
          />
        </TextField.Root>
        <table>
          <thead>
            <tr>
              <th>
                <button type='button' onClick={addSubscription()}>
                  +
                </button>
              </th>
              <th>User name</th>
            </tr>
          </thead>
          <tbody>
            <Index each={subscriptions()}>
              {(_, index) => (
                <tr>
                  <td>
                    <button type='button' onClick={removeSubscription(index)}>
                      -
                    </button>
                  </td>
                  <td>
                    <TextField.Root>
                      <TextField.Input
                        type='text'
                        name={`subscriptions.${index}.username`}
                        required={true}
                        placeholder='user name'
                      />
                    </TextField.Root>
                  </td>
                </tr>
              )}
            </Index>
          </tbody>
        </table>
        <Switch>
          <Match when={!isNew()}>
            <Button.Root type='submit' disabled={!isDirty() || !isValid()}>
              Save
            </Button.Root>
            <Button.Root onclick={deleteHandler}>Delete</Button.Root>
          </Match>
          <Match when={isNew()}>
            <Button.Root type='submit' isDisabled={!isValid()}>
              Create
            </Button.Root>
          </Match>
        </Switch>
        <Button.Root onclick={cancelHandler}>Back</Button.Root>
      </form>
    </>
  );
};

export default User;
