// src/client/entities/employee/model/useEmployeeForm.ts
// Composable for employee form management with validation, phone formatting, and data population

import { ref, computed, watch, nextTick } from 'vue';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc.js';
import timezone from 'dayjs/plugin/timezone.js';
import { employeeRepository } from '@client/shared/api/repositories/EmployeeRepository';
import { formatPhoneNumberAsYouType, isValidPhoneNumber } from '@shared/utils/formatters';
import { useMaidPeriods, type MaidPeriod } from './useMaidPeriods';

dayjs.extend(utc);
dayjs.extend(timezone);

export interface EmployeeFormOptions {
  employee: () => any;
  mode: () => 'create' | 'edit';
}

export interface FormData {
  fullName: string;
  position: string;
  phone: string;
  email: string;
  birthDate: string;
  address: string;
  notes: string;
  hireDate: string;
  archivedAt: string;
  createUser: boolean;
  username: string;
  password: string;
  role: string;
  isMaidAlso: boolean;
  isFired: boolean;
  firedReason: string;
}

export function useEmployeeForm(options: EmployeeFormOptions) {
  // Compose useMaidPeriods for maid periods management
  const {
    maidPeriods,
    deletedMaidPeriods,
    addMaidPeriod,
    removeMaidPeriod,
    undoRemoveMaidPeriod,
    endMaidPeriod,
    reopenMaidPeriod,
    getMaidPeriodStatus,
    showMaidPeriodsSection: maidPeriodsSectionVisible,
    maidPeriodsSectionTitle: maidPeriodsSectionTitleComputed,
    isSaveDisabled: maidPeriodsOverlapDisabled,
  } = useMaidPeriods();

  // State
  const formData = ref<FormData>({
    fullName: '',
    position: '',
    phone: '',
    email: '',
    birthDate: '',
    address: '',
    notes: '',
    hireDate: '',
    archivedAt: '',
    createUser: false,
    username: '',
    password: '',
    role: 'MANAGER',
    isMaidAlso: false,
    isFired: false,
    firedReason: '',
  });

  const errors = ref<Record<string, string>>({});
  const loading = ref(false);
  const usernameChecking = ref(false);
  const usernameAvailable = ref<boolean | null>(null);

  // Computed property to check if employee has existing user account
  const hasExistingUser = computed(() => {
    const mode = options.mode();
    const employee = options.employee();
    return mode === 'edit' && employee?.username;
  });

  // Computed property to check if maid periods section should be shown
  const showMaidPeriodsSection = computed(() => {
    // Для MAID и MANAGER секция должна быть всегда доступна,
    // чтобы можно было управлять периодами (включая создание первого периода).
    return formData.value.role === 'MAID' || formData.value.role === 'MANAGER';
  });

  // Computed property for dynamic section title
  const maidPeriodsSectionTitle = computed(() => {
    return formData.value.role === 'MANAGER' ? 'Управление ролью горничной' : 'Периоды работы (Горничная)';
  });

  // Computed property to disable save button based on validation
  const isSaveDisabled = computed(() => {
    // Disable if username is taken
    if (formData.value.createUser && usernameAvailable.value === false) {
      return true;
    }
    // Check for maid periods overlap
    if (maidPeriodsOverlapDisabled.value) {
      return true;
    }
    return false;
  });

  // Computed class for username input based on availability
  const usernameInputClass = computed(() => {
    if (usernameAvailable.value === false) {
      return 'border-red-500 focus:border-red-500 focus:ring-red-500';
    }
    if (usernameAvailable.value === true && formData.value.username.length >= 3) {
      return 'border-green-500 focus:border-green-500 focus:ring-green-500';
    }
    return '';
  });

  // Clear error for a specific field
  const clearFieldError = (fieldName: string) => {
    if (errors.value[fieldName]) {
      errors.value[fieldName] = '';
    }
  };

  // Handle phone input with manual control mode
  const handlePhoneInput = (event: Event) => {
    const target = event.target as HTMLInputElement;
    const rawValue = target.value;

    // Запоминаем позицию курсора
    const cursor = target.selectionStart || 0;

    // Защита от вставки (Paste): принудительная очистка через replace(/[^\d\s()\-]/g, '')
    // ПЕРЕД тем, как присвоить значение в formData.phone
    const cleaned = rawValue.replace(/[^\d\s()\-]/g, '');

    // Фильтруем ввод: пропускаем только цифры, пробелы, скобки (), дефисы -
    // Любые другие символы (буквы, спецсимволы) вырезаются на лету
    const filtered = formatPhoneNumberAsYouType(cleaned);

    // Обновляем состояние поля ввода
    formData.value.phone = filtered;

    // После обновления Vue (nextTick) возвращаем курсор на ту же позицию
    nextTick(() => {
      const newValue = target.value;
      // Если строка стала короче (из-за вырезания символов), корректируем позицию
      const newPos = Math.min(cursor, newValue.length);
      target.setSelectionRange(newPos, newPos);
    });

    clearFieldError('phone');
  };

  // Debounce utility function
  function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void {
    let timeout: ReturnType<typeof setTimeout> | null = null;
    return function(...args: Parameters<T>) {
      if (timeout !== null) {
        clearTimeout(timeout);
      }
      timeout = setTimeout(() => func(...args), wait);
    };
  }

  // Check username availability
  const checkUsername = async (username: string) => {
    if (!username || username.length < 3) {
      usernameAvailable.value = null;
      return;
    }

    usernameChecking.value = true;
    try {
      const response = await employeeRepository.checkUsername(username);
      // API interceptor already extracts data.data, so response is the object directly
      usernameAvailable.value = response.available;
    } catch (err) {
      console.error('Error checking username:', err);
      usernameAvailable.value = null;
    } finally {
      usernameChecking.value = false;
    }
  };

  // Debounced version of checkUsername
  const debouncedCheckUsername = debounce(checkUsername, 500);

  // Watch username for real-time availability check
  watch(() => formData.value.username, (newUsername, oldUsername) => {
    // Check if createUser is enabled OR in edit mode with existing user
    const shouldCheck = (formData.value.createUser || hasExistingUser.value) && newUsername;
    
    if (shouldCheck) {
      // In edit mode, only check if username was actually changed
      if (options.mode() === 'edit' && hasExistingUser.value) {
        const originalUsername = options.employee()?.username || '';
        if (newUsername !== originalUsername) {
          debouncedCheckUsername(newUsername);
        } else {
          usernameAvailable.value = null;
        }
      } else {
        debouncedCheckUsername(newUsername);
      }
    } else {
      usernameAvailable.value = null;
    }
  });

  // Watch createUser to reset username availability when toggled
  watch(() => formData.value.createUser, (newValue) => {
    if (!newValue) {
      usernameAvailable.value = null;
    }
  });

  // Watch role to reset username availability when role changes
  watch(() => formData.value.role, () => {
    usernameAvailable.value = null;
  });

  // Watch for employee changes to populate form in edit mode
  watch(() => options.employee(), (newEmployee) => {
    if (options.mode() === 'edit' && newEmployee) {
      // Миграция данных: если телефон начинается с +, обрезаем его
      // чтобы в инпуте не висел дубликат рядом с захардкоженным плюсом
      const phoneValue = newEmployee.phone || '';
      const phoneWithoutPlus = phoneValue.startsWith('+') ? phoneValue.substring(1) : phoneValue;

      formData.value = {
        fullName: newEmployee.fullName || '',
        position: newEmployee.position || '',
        // Сохраняем телефон без плюса (так как плюс теперь живет в UI)
        phone: phoneWithoutPlus,
        email: newEmployee.email || '',
        birthDate: newEmployee.birthDate ? dayjs(newEmployee.birthDate).tz('Europe/Moscow').format('YYYY-MM-DD') : '',
        address: newEmployee.address || '',
        notes: newEmployee.notes || '',
        hireDate: newEmployee.createdAt ? dayjs(newEmployee.createdAt).tz('Europe/Moscow').format('YYYY-MM-DD') : '',
        archivedAt: newEmployee.archivedAt ? dayjs(newEmployee.archivedAt).tz('Europe/Moscow').format('YYYY-MM-DD') : '',
        createUser: false,
        username: newEmployee.username || '',
        password: '',
        role: newEmployee.role || 'MANAGER',
        isMaidAlso: newEmployee.isMaidAlso || false,
        isFired: newEmployee.isFired || false,
        firedReason: newEmployee.firedReason || '',
      };
      // Populate maid periods
      maidPeriods.value = newEmployee.maidPeriods || [];
      deletedMaidPeriods.value = [];
    }
  }, { immediate: true });

  // Обёртка для addMaidPeriod — подставляет дату приёма
  const addMaidPeriodWithHireDate = () => {
    addMaidPeriod(formData.value.hireDate || undefined);
  };

  // При изменении даты приёма — обновляем startDate периодов,
  // если их текущая startDate меньше новой даты приёма.
  // Также сбрасываем endDate в null, если(startDate > endDate),
  // чтобы период оставался открытым и не ломался при сдвиге даты.
  watch(() => formData.value.hireDate, (newHireDate, oldHireDate) => {
    if (!newHireDate) return;
    maidPeriods.value.forEach(period => {
      if (period._deleted) return;
      if (period.startDate < newHireDate) {
        period.startDate = newHireDate;
        if (period.endDate && period.endDate <= newHireDate) {
          period.endDate = null;
        }
      }
    });
  });

  // Watch for role changes to auto-create default period for new MAID employees
  watch(() => formData.value.role, (newRole, oldRole) => {
    // Автоматизация для новых сотрудников: при создании сотрудника с ролью Горничная,
    // если список периодов пуст, автоматически добавляем один дефолтный период
    if (options.mode() === 'create' && newRole === 'MAID' && oldRole !== 'MAID' && maidPeriods.value.length === 0) {
      addMaidPeriodWithHireDate();
    }
  });

  const resetForm = () => {
    formData.value = {
      fullName: '',
      position: '',
      phone: '',
      email: '',
      birthDate: '',
      address: '',
      notes: '',
      hireDate: '',
      archivedAt: '',
      createUser: false,
      username: '',
      password: '',
      role: 'MANAGER',
      isMaidAlso: false,
      isFired: false,
      firedReason: '',
    };
    maidPeriods.value = [];
    deletedMaidPeriods.value = [];
    errors.value = {};
    usernameAvailable.value = null;
  };

  const validate = () => {
    errors.value = {};

    if (!formData.value.fullName.trim()) {
      errors.value.fullName = 'ФИО обязательно';
    }

    if (!formData.value.position.trim()) {
      errors.value.position = 'Должность обязательна';
    }

    if (!formData.value.phone.trim()) {
      errors.value.phone = 'Телефон обязателен';
    } else {
      // Проверяем валидность номера телефона через isValidPhoneNumber
      // Функция очищает строку через cleanPhoneNumber и проверяет длину (10-15 цифр)
      if (!isValidPhoneNumber(formData.value.phone)) {
        errors.value.phone = 'Некорректный номер (10-15 цифр)';
      }
    }

    // Email is now optional
    if (formData.value.email.trim() && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.value.email)) {
      errors.value.email = 'Некорректный формат email';
    }

    if (formData.value.createUser) {
      // Exclude username and password validation for MAID role
      const isMaid = formData.value.role === 'MAID';
      if (!isMaid) {
        // Username is required for non-MAID roles
        if (!formData.value.username.trim()) {
          errors.value.username = 'Имя пользователя обязательно';
        } else if (formData.value.username.length < 3) {
          errors.value.username = 'Минимум 3 символа';
        } else if (usernameAvailable.value === false) {
          errors.value.username = 'Имя пользователя занято';
        }

        // Password is required for non-MAID roles
        if (!formData.value.password) {
          errors.value.password = 'Пароль обязателен';
        } else if (formData.value.password.length < 6) {
          errors.value.password = 'Минимум 6 символов';
        }
      }
    }

    // In edit mode with existing user, validate username and password for non-MAID roles only
    if (options.mode() === 'edit' && hasExistingUser.value) {
      const isMaid = formData.value.role === 'MAID';
      
      // Skip validation for MAID role
      if (!isMaid) {
        const originalUsername = options.employee()?.username || '';
        
        // Validate username only if it was changed
        if (formData.value.username !== originalUsername) {
          if (!formData.value.username.trim()) {
            errors.value.username = 'Логин обязателен';
          } else if (formData.value.username.length < 3) {
            errors.value.username = 'Минимум 3 символа';
          } else if (usernameAvailable.value === false) {
            errors.value.username = 'Логин занят';
          }
        }
        
        // Validate password if provided
        if (formData.value.password && formData.value.password.length < 6) {
          errors.value.password = 'Минимум 6 символов';
        }
      }
    }

    // Validate maid periods (exclude deleted periods)
    const activePeriods = maidPeriods.value.filter(p => !p._deleted);
    if (activePeriods.length > 0) {
      const today = dayjs().tz('Europe/Moscow').startOf('day').toDate();
      
      for (let i = 0; i < activePeriods.length; i++) {
        const period = activePeriods[i];
        // Find original index for error key
        const originalIndex = maidPeriods.value.findIndex(p => p === period);
        
        if (!period.startDate) {
          errors.value[`maidPeriod_${originalIndex}_startDate`] = 'Дата начала обязательна';
        }
        
        if (period.endDate && dayjs(period.startDate).tz('Europe/Moscow').startOf('day').toDate() > dayjs(period.endDate).tz('Europe/Moscow').startOf('day').toDate()) {
          errors.value[`maidPeriod_${originalIndex}_endDate`] = 'Дата окончания не может быть раньше даты начала';
        }
      }
    }

    return Object.keys(errors.value).length === 0;
  };

  const saveEmployee = async () => {
    if (!validate()) {
      return false;
    }

    loading.value = true;
    try {
      // Send all periods with id, add _deleted flag for deleted ones
      // Exclude new periods (without id) that were marked as deleted
      const maidPeriodsPayload = maidPeriods.value
        .filter(p => p.id || !p._deleted)
        .map(p => ({
          id: p.id,
          startDate: p.startDate,
          endDate: p.endDate,
          _deleted: p._deleted || false,
        }));

      // Двойной контроль: прогоняем payload.phone через фильтр еще раз
      // Это гарантирует, что в базу улетит только то, что мы разрешили,
      // даже если юзер как-то обманул инпут
      const phoneCleaned = formData.value.phone.replace(/[^\d\s()\-]/g, '');

      const payload: any = {
        fullName: formData.value.fullName,
        position: formData.value.position,
        // Сохраняем телефон "как есть" (авторский формат с скобками, пробелами)
        // но БЕЗ символа плюса (так как плюс теперь живет в UI)
        phone: phoneCleaned,
        email: formData.value.email,
        // Send empty strings instead of undefined - backend will handle them
        address: formData.value.address || '',
        notes: formData.value.notes || '',
        // Include fired reason and status
        firedReason: formData.value.firedReason || null,
        isFired: formData.value.isFired,
        // Include maid periods (with _deleted flag for backend processing)
        // isMaidAlso is computed by backend based on active maid periods
        maidPeriods: maidPeriodsPayload.length > 0 ? maidPeriodsPayload : undefined,
      };

      // Send birthDate as ISO string if present, otherwise empty string
      if (formData.value.birthDate) {
        payload.birthDate = dayjs(formData.value.birthDate).utc().toISOString();
      } else {
        payload.birthDate = '';
      }

      // Send hireDate as ISO string if present
      if (formData.value.hireDate) {
        payload.hireDate = dayjs(formData.value.hireDate).utc().toISOString();
      }

      // Send archivedAt as ISO string if employee is fired
      if (formData.value.isFired && formData.value.archivedAt) {
        payload.archivedAt = dayjs(formData.value.archivedAt).tz('Europe/Moscow').startOf('day').utc().toISOString();
      }

      // In create mode, handle user creation
      if (options.mode() === 'create' && formData.value.createUser) {
        payload.createUser = true;
        // For MAID role, generate random username; for other roles use form data
        if (formData.value.role === 'MAID') {
          payload.username = 'maid_' + Math.random().toString(36).substring(2, 8);
        } else {
          payload.username = formData.value.username;
        }
        // For MAID role, password is not sent (default password will be used on backend)
        // For other roles, password is required
        if (formData.value.role !== 'MAID') {
          payload.password = formData.value.password;
        }
        payload.role = formData.value.role;
      }

      // In edit mode with existing user, allow updating role and maidPeriods
      // Username is not sent for MAID role (prevents overwriting generated hash)
      if (options.mode() === 'edit' && hasExistingUser.value) {
        // Only send username for non-MAID roles
        if (formData.value.role !== 'MAID') {
          payload.username = formData.value.username;
        }
        // Send role from formData - allows changing the role
        payload.role = formData.value.role || 'MANAGER';
        // For MAID role, password is not sent (default password will be used if needed)
        // For other roles, send password field - empty string means "no change", non-empty means "update"
        if (formData.value.role !== 'MAID') {
          payload.password = formData.value.password || '';
        }
        // Always send maidPeriods in edit mode to allow updating them
        payload.maidPeriods = maidPeriodsPayload.length > 0 ? maidPeriodsPayload : undefined;
      }

      // In edit mode without existing user, allow creating an account from checkbox
      if (options.mode() === 'edit' && !hasExistingUser.value && formData.value.createUser) {
        payload.createUser = true;
        payload.role = formData.value.role;

        // Для MAID логин генерируется автоматически (как при создании)
        if (formData.value.role === 'MAID') {
          payload.username = 'maid_' + Math.random().toString(36).substring(2, 8);
        } else {
          payload.username = formData.value.username;
          payload.password = formData.value.password;
        }
      }

      if (options.mode() === 'create') {
        await employeeRepository.create(payload);
      } else {
        await employeeRepository.update(options.employee().id, payload);
      }

      return true;
    } catch (err: any) {
      console.error('Error saving employee:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };

  return {
    // State
    formData,
    errors,
    loading,
    usernameChecking,
    usernameAvailable,

    // Computed
    hasExistingUser,
    showMaidPeriodsSection,
    maidPeriodsSectionTitle,
    isSaveDisabled,
    usernameInputClass,

    // Maid periods (from useMaidPeriods)
    maidPeriods,
    deletedMaidPeriods,
    getMaidPeriodStatus,

    // Actions
    clearFieldError,
    handlePhoneInput,
    checkUsername,
    addMaidPeriod: addMaidPeriodWithHireDate,
    removeMaidPeriod,
    undoRemoveMaidPeriod,
    endMaidPeriod,
    reopenMaidPeriod,
    resetForm,
    validate,
    saveEmployee,
  };
}
