import { omit } from 'lodash-es';
import { useMemo } from 'react';
import z from 'zod';
import { m } from '../../../../paraglide/messages';
import { EditPageControls } from '../../../../shared/components/EditPageControls/EditPageControls';
import { EditPageFormSection } from '../../../../shared/components/EditPageFormSection/EditPageFormSection';
import { Fold } from '../../../../shared/defguard-ui/components/Fold/Fold';
import { SizedBox } from '../../../../shared/defguard-ui/components/SizedBox/SizedBox';
import { ThemeSpacing } from '../../../../shared/defguard-ui/types';
import { useAppForm } from '../../../../shared/form';
import { formChangeLogic } from '../../../../shared/formLogic';
import { joinCsv } from '../../../../shared/utils/csv';
import {
  directorySyncBehaviorOptions,
  directorySyncTargetOptions,
  formatMicrosoftBaseUrl,
  providerUsernameHandlingOptions,
} from '../../../AddExternalOpenIdWizardPage/consts';
import {
  baseExternalProviderConfigSchema,
  microsoftProviderSyncSchema,
} from '../../../AddExternalOpenIdWizardPage/steps/AddExternalOpenIdDirectoryStep/forms/schemas';
import type { EditProviderFormProps } from '../types';

const basicSchema = z
  .object({
    directory_sync_enabled: z.boolean(),
    microsoftTenantId: z
      .string(m.form_error_required())
      .trim()
      .min(1, m.form_error_required()),
    directory_sync_group_match: z.string().trim().nullable(),
    directory_sync_user_groups: z.string().trim().nullable(),
  })
  .extend(omit(baseExternalProviderConfigSchema.shape, ['base_url']));

const syncSchema = basicSchema.extend(microsoftProviderSyncSchema.shape);

const discriminatedSchema = z.discriminatedUnion('directory_sync_enabled', [
  basicSchema,
  syncSchema,
]);

const validationSchema = syncSchema
  .omit({ directory_sync_interval: true })
  .extend({ directory_sync_interval: z.number() })
  .superRefine((val, ctx) => {
    if (
      val.directory_sync_enabled &&
      (typeof val.directory_sync_interval !== 'number' ||
        val.directory_sync_interval < 60)
    ) {
      ctx.addIssue({
        path: ['directory_sync_interval'],
        code: 'custom',
        message: m.form_error_min({ value: 60 }),
      });
    }
  });

type FormFields = z.infer<typeof discriminatedSchema>;

export const EditMicrosoftProviderForm = ({
  provider,
  onDelete,
  onSubmit,
}: EditProviderFormProps) => {
  const defaultValues = useMemo((): FormFields => {
    const urlParts = provider.base_url.split('/');
    const tenantId = urlParts[urlParts.length - 2] ?? '';
    return {
      client_id: provider.client_id,
      client_secret: provider.client_secret,
      create_account: provider.create_account,
      display_name: provider.display_name,
      username_handling: provider.username_handling,
      directory_sync_admin_behavior: provider.directory_sync_admin_behavior,
      directory_sync_interval: provider.directory_sync_interval,
      directory_sync_target: provider.directory_sync_target,
      directory_sync_user_behavior: provider.directory_sync_user_behavior,
      directory_sync_enabled: provider.directory_sync_enabled,
      prefetch_users: provider.prefetch_users ?? false,
      directory_sync_group_match: joinCsv(
        Array.isArray(provider.directory_sync_group_match)
          ? provider.directory_sync_group_match
          : provider.directory_sync_group_match
            ? [provider.directory_sync_group_match]
            : null,
      ),
      directory_sync_user_groups: joinCsv(
        Array.isArray(provider.directory_sync_user_groups)
          ? provider.directory_sync_user_groups
          : provider.directory_sync_user_groups
            ? [provider.directory_sync_user_groups]
            : null,
      ),
      microsoftTenantId: tenantId,
    };
  }, [provider]);

  const form = useAppForm({
    defaultValues,
    validationLogic: formChangeLogic,
    validators: {
      onSubmit: validationSchema,
      onChange: validationSchema,
    },
    onSubmit: async ({ value }) => {
      const base_url = formatMicrosoftBaseUrl(value.microsoftTenantId);
      await onSubmit({
        ...value,
        base_url,
        directory_sync_group_match: value.directory_sync_group_match ?? '',
        directory_sync_user_groups: value.directory_sync_user_groups ?? '',
      });
    },
  });

  return (
    <form
      onSubmit={(e) => {
        e.stopPropagation();
        e.preventDefault();
        form.handleSubmit();
      }}
    >
      <form.AppForm>
        <EditPageFormSection label={m.settings_openid_provider_client_settings_title()}>
          <form.AppField name="display_name">
            {(field) => (
              <field.FormInput
                required
                label={m.settings_openid_provider_label_display_name()}
                helper={m.settings_openid_provider_helper_display_name()}
              />
            )}
          </form.AppField>
          <SizedBox height={ThemeSpacing.Xl2} />
          <form.AppField name="microsoftTenantId">
            {(field) => (
              <field.FormInput
                required
                label={m.settings_openid_provider_label_microsoft_tenant_id()}
                helper={m.settings_openid_provider_helper_microsoft_tenant_id()}
              />
            )}
          </form.AppField>
          <SizedBox height={ThemeSpacing.Xl2} />
          <form.AppField name="client_id">
            {(field) => (
              <field.FormInput
                required
                label={m.settings_openid_provider_label_client_id()}
                helper={m.settings_openid_provider_helper_client_id()}
              />
            )}
          </form.AppField>
          <SizedBox height={ThemeSpacing.Xl2} />
          <form.AppField name="client_secret">
            {(field) => (
              <field.FormInput
                type="password"
                required
                label={m.settings_openid_provider_label_client_secret()}
                helper={m.settings_openid_provider_helper_client_secret()}
              />
            )}
          </form.AppField>
          <SizedBox height={ThemeSpacing.Xl2} />
          <form.AppField name="username_handling">
            {(field) => (
              <field.FormSelect
                options={providerUsernameHandlingOptions}
                label={m.settings_openid_provider_label_username_handling()}
                helper={m.settings_openid_provider_helper_username_handling()}
              />
            )}
          </form.AppField>
          <SizedBox height={ThemeSpacing.Xl2} />
          <form.AppField name="create_account">
            {(field) => (
              <field.FormInteractiveBlock
                variant="checkbox"
                title={m.settings_openid_provider_create_account_title()}
                content={m.settings_openid_provider_create_account_content()}
              />
            )}
          </form.AppField>
        </EditPageFormSection>
        <EditPageFormSection label={m.settings_openid_provider_directory_sync_title()}>
          <form.AppField name="directory_sync_enabled">
            {(field) => (
              <field.FormToggle
                label={m.settings_openid_provider_directory_sync_toggle()}
              />
            )}
          </form.AppField>
          <form.Subscribe selector={(s) => s.values.directory_sync_enabled}>
            {(enabled) => (
              <Fold open={enabled}>
                <SizedBox height={ThemeSpacing.Xl3} />
                <form.AppField name="directory_sync_target">
                  {(field) => (
                    <field.FormSelect
                      options={directorySyncTargetOptions}
                      label={m.settings_openid_provider_label_sync_target()}
                      helper={m.settings_openid_provider_helper_sync_target()}
                    />
                  )}
                </form.AppField>
                <SizedBox height={ThemeSpacing.Xl2} />
                <form.AppField name="directory_sync_interval">
                  {(field) => (
                    <field.FormInput
                      required
                      label={m.settings_openid_provider_label_sync_interval()}
                      type="number"
                      helper={m.settings_openid_provider_helper_sync_interval()}
                    />
                  )}
                </form.AppField>
                <SizedBox height={ThemeSpacing.Xl2} />
                <form.AppField name="directory_sync_user_behavior">
                  {(field) => (
                    <field.FormSelect
                      options={directorySyncBehaviorOptions}
                      label={m.settings_openid_provider_label_sync_user_behavior()}
                      helper={m.settings_openid_provider_helper_sync_user_behavior()}
                    />
                  )}
                </form.AppField>
                <SizedBox height={ThemeSpacing.Xl2} />
                <form.AppField name="directory_sync_admin_behavior">
                  {(field) => (
                    <field.FormSelect
                      options={directorySyncBehaviorOptions}
                      label={m.settings_openid_provider_label_sync_admin_behavior()}
                      helper={m.settings_openid_provider_helper_sync_admin_behavior()}
                    />
                  )}
                </form.AppField>
                <SizedBox height={ThemeSpacing.Xl2} />
                <form.AppField name="directory_sync_group_match">
                  {(field) => (
                    <field.FormInput
                      label={m.settings_openid_provider_label_sync_only_matching_groups()}
                      helper={m.settings_openid_provider_helper_microsoft_group_match()}
                    />
                  )}
                </form.AppField>
                <SizedBox height={ThemeSpacing.Xl2} />
                <form.AppField name="directory_sync_user_groups">
                  {(field) => (
                    <field.FormInput
                      label={m.settings_openid_provider_label_sync_users_from_groups()}
                      helper={m.settings_openid_provider_helper_sync_users_from_groups()}
                    />
                  )}
                </form.AppField>
                <SizedBox height={ThemeSpacing.Xl2} />
                <form.AppField name="prefetch_users">
                  {(field) => (
                    <field.FormCheckbox
                      text={m.settings_openid_provider_prefetch_users()}
                    />
                  )}
                </form.AppField>
              </Fold>
            )}
          </form.Subscribe>
        </EditPageFormSection>
        <form.Subscribe selector={(s) => s.isSubmitting}>
          {(submitting) => (
            <EditPageControls
              deleteProps={{
                disabled: submitting,
                text: m.settings_openid_provider_delete_button(),
                onClick: onDelete,
              }}
              cancelProps={{
                text: m.controls_cancel(),
                disabled: submitting,
                onClick: () => {
                  window.history.back();
                },
              }}
              submitProps={{
                text: m.controls_save_changes(),
                loading: submitting,
                type: 'submit',
                onClick: () => {
                  form.handleSubmit();
                },
              }}
            />
          )}
        </form.Subscribe>
      </form.AppForm>
    </form>
  );
};
