// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { FormEvent } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { v4 as uuid } from 'uuid';
import { z } from 'zod';
import { Modal } from './Modal.dom.tsx';
import type { LocalizerType } from '../types/I18N.std.ts';
import { Avatar, AvatarSize } from './Avatar.dom.tsx';
import type {
  ConversationType,
  NicknameAndNote,
} from '../state/ducks/conversations.preload.ts';
import { Input } from './Input.dom.tsx';
import { AutoSizeTextArea } from './AutoSizeTextArea.dom.tsx';
import { Button, ButtonVariant } from './Button.dom.tsx';
import { strictAssert } from '../util/assert.std.ts';
import { safeParsePartial } from '../util/schemas.std.ts';

const formSchema = z.object({
  nickname: z
    .object({
      givenName: z.string().nullable(),
      familyName: z.string().nullable(),
    })
    .nullable(),
  note: z.string().nullable(),
});

function toOptionalStringValue(value: string): string | null {
  const trimmed = value.trim();
  return trimmed === '' ? null : trimmed;
}

export type EditNicknameAndNoteModalProps = Readonly<{
  conversation: ConversationType;
  i18n: LocalizerType;
  onSave: (result: NicknameAndNote) => void;
  onClose: () => void;
}>;

export function EditNicknameAndNoteModal({
  conversation,
  i18n,
  onSave,
  onClose,
}: EditNicknameAndNoteModalProps): React.JSX.Element {
  strictAssert(
    conversation.type === 'direct',
    'Expected a direct conversation'
  );

  const [givenName, setGivenName] = useState(
    conversation.nicknameGivenName ?? ''
  );
  const [familyName, setFamilyName] = useState(
    conversation.nicknameFamilyName ?? ''
  );
  const [note, setNote] = useState(conversation.note ?? '');

  const [formId] = useState(() => uuid());
  const [givenNameId] = useState(() => uuid());
  const [familyNameId] = useState(() => uuid());
  const [noteId] = useState(() => uuid());

  const formResult = useMemo(() => {
    const givenNameValue = toOptionalStringValue(givenName);
    const familyNameValue = toOptionalStringValue(familyName);
    const noteValue = toOptionalStringValue(note);
    const hasEitherName = givenNameValue != null || familyNameValue != null;
    return safeParsePartial(formSchema, {
      nickname: hasEitherName
        ? { givenName: givenNameValue, familyName: familyNameValue }
        : null,
      note: noteValue,
    });
  }, [givenName, familyName, note]);

  const handleSubmit = useCallback(
    (event: FormEvent) => {
      event.preventDefault();
      if (formResult.success) {
        onSave(formResult.data);
        onClose();
      }
    },
    [formResult, onSave, onClose]
  );

  return (
    <Modal
      modalName="EditNicknameAndNoteModal"
      moduleClassName="EditNicknameAndNoteModal"
      i18n={i18n}
      onClose={onClose}
      title={i18n('icu:EditNicknameAndNoteModal__Title')}
      hasXButton
      modalFooter={
        <>
          <Button variant={ButtonVariant.Secondary} onClick={onClose}>
            {i18n('icu:cancel')}
          </Button>
          <Button
            variant={ButtonVariant.Primary}
            type="submit"
            form={formId}
            aria-disabled={!formResult.success}
          >
            {i18n('icu:save')}
          </Button>
        </>
      }
    >
      <p className="EditNicknameAndNoteModal__Description">
        {i18n('icu:EditNicknameAndNoteModal__Description')}
      </p>
      <div className="EditNicknameAndNoteModal__Avatar">
        <Avatar
          {...conversation}
          conversationType={conversation.type}
          i18n={i18n}
          size={AvatarSize.EIGHTY}
          badge={undefined}
          theme={undefined}
        />
      </div>
      <form id={formId} onSubmit={handleSubmit}>
        <label
          htmlFor={givenNameId}
          className="EditNicknameAndNoteModal__Label"
        >
          {i18n('icu:EditNicknameAndNoteModal__FirstName__Label')}
        </label>
        <Input
          id={givenNameId}
          i18n={i18n}
          placeholder={i18n(
            'icu:EditNicknameAndNoteModal__FirstName__Placeholder'
          )}
          value={givenName}
          hasClearButton
          maxLengthCount={26}
          maxByteCount={128}
          onChange={value => {
            setGivenName(value);
          }}
        />
        <label
          htmlFor={familyNameId}
          className="EditNicknameAndNoteModal__Label"
        >
          {i18n('icu:EditNicknameAndNoteModal__LastName__Label')}
        </label>
        <Input
          id={familyNameId}
          i18n={i18n}
          placeholder={i18n(
            'icu:EditNicknameAndNoteModal__LastName__Placeholder'
          )}
          value={familyName}
          hasClearButton
          maxLengthCount={26}
          maxByteCount={128}
          onChange={value => {
            setFamilyName(value);
          }}
        />

        <label htmlFor={noteId} className="EditNicknameAndNoteModal__Label">
          {i18n('icu:EditNicknameAndNoteModal__Note__Label')}
        </label>
        <AutoSizeTextArea
          i18n={i18n}
          id={noteId}
          placeholder={i18n('icu:EditNicknameAndNoteModal__Note__Placeholder')}
          value={note}
          maxByteCount={240}
          maxLengthCount={240}
          whenToShowRemainingCount={140}
          whenToWarnRemainingCount={235}
          onChange={value => {
            setNote(value);
          }}
        />
        <button type="submit" hidden>
          {i18n('icu:submit')}
        </button>
      </form>
    </Modal>
  );
}
