import {
  useCallback,
  useEffect,
  useMemo,
  useState,
  type FormEvent,
} from 'react'
import * as Dialog from '@radix-ui/react-dialog'
import {
  Check,
  Clock3,
  Download,
  FileSpreadsheet,
  FileText,
  Search,
  UsersRound,
  X,
} from 'lucide-react'

import { usersService } from '../../../../entities/employee/api/usersService'
import type { Employee } from '../../../../entities/employee/model/types'
import {
  fleetReportSchedulesService,
} from '../../../../entities/report/api/fleetReportSchedulesService'
import { fleetReportService } from '../../../../entities/report/api/fleetReportService'
import type {
  FleetReportFormat,
  FleetReportSchedule,
} from '../../../../entities/report/model/types'
import { MotionDialogContent } from '../../../../shared/ui/MotionDialog/MotionDialog'
import {
  getEmployeeFullName,
  getEmployeeRoleLabel,
} from '../../lib/employeeFormatters'

import './FleetReportScheduleModal.scss'

type FleetReportScheduleModalProps = {
  open: boolean
  onOpenChange: (open: boolean) => void
  onSuccess?: (schedule: FleetReportSchedule) => void | Promise<void>
}

const reportFormatOptions: Array<{
  value: FleetReportFormat
  label: string
}> = [
  {
    value: 'PDF',
    label: 'PDF',
  },
  {
    value: 'XLSX',
    label: 'Excel',
  },
]

function getUserInitials(employee: Employee) {
  const first = employee.lastName?.trim()[0] ?? ''
  const second = employee.firstName?.trim()[0] ?? ''

  return `${first}${second}`.toUpperCase() || '??'
}

function getRecipientSearchText(employee: Employee) {
  return [
    employee.lastName,
    employee.firstName,
    employee.middleName,
    employee.email,
    employee.login,
    employee.username,
  ]
    .filter(Boolean)
    .join(' ')
    .toLowerCase()
}

export function FleetReportScheduleModal({
  open,
  onOpenChange,
  onSuccess,
}: FleetReportScheduleModalProps) {
  const [users, setUsers] = useState<Employee[]>([])
  const [usersLoading, setUsersLoading] = useState(false)
  const [usersError, setUsersError] = useState<string | null>(null)
  const [recipientSearch, setRecipientSearch] = useState('')
  const [selectedUserIds, setSelectedUserIds] = useState<number[]>([])
  const [reportFormat, setReportFormat] = useState<FleetReportFormat>('PDF')
  const [sendTime, setSendTime] = useState('09:00')
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [isGeneratingReport, setIsGeneratingReport] = useState(false)
  const [submitError, setSubmitError] = useState<string | null>(null)

  useEffect(() => {
    if (!open) return

    const frameId = window.requestAnimationFrame(() => {
      setRecipientSearch('')
      setSelectedUserIds([])
      setReportFormat('PDF')
      setSendTime('09:00')
      setSubmitError(null)
    })

    return () => {
      window.cancelAnimationFrame(frameId)
    }
  }, [open])

  useEffect(() => {
    if (!open) return

    let isMounted = true

    async function fetchUsers() {
      try {
        setUsersLoading(true)
        setUsersError(null)

        const response = await usersService.getUsers({
          page: 0,
          pageSize: 1000,
          sortDirection: 'ASC',
          sortField: 'Name',
        })

        if (isMounted) {
          setUsers(response.page)
        }
      } catch {
        if (isMounted) {
          setUsersError('Не удалось загрузить пользователей')
        }
      } finally {
        if (isMounted) {
          setUsersLoading(false)
        }
      }
    }

    fetchUsers()

    return () => {
      isMounted = false
    }
  }, [open])

  const filteredUsers = useMemo(() => {
    const query = recipientSearch.trim().toLowerCase()

    if (!query) return users

    return users.filter((user) => getRecipientSearchText(user).includes(query))
  }, [recipientSearch, users])

  const selectedUsers = useMemo(() => {
    const selectedIds = new Set(selectedUserIds)

    return users.filter((user) => selectedIds.has(user.id))
  }, [selectedUserIds, users])

  const filteredUserIds = useMemo(
    () => filteredUsers.map((user) => user.id),
    [filteredUsers],
  )
  const selectedUserIdsSet = useMemo(
    () => new Set(selectedUserIds),
    [selectedUserIds],
  )
  const areAllFilteredUsersSelected =
    filteredUserIds.length > 0 &&
    filteredUserIds.every((userId) => selectedUserIdsSet.has(userId))
  const canSubmit =
    selectedUserIds.length > 0 &&
    Boolean(sendTime) &&
    !usersLoading &&
    !isSubmitting

  const handleSelectAllFiltered = useCallback(() => {
    setSelectedUserIds((currentUserIds) => {
      const nextUserIds = new Set(currentUserIds)

      filteredUserIds.forEach((userId) => {
        nextUserIds.add(userId)
      })

      return Array.from(nextUserIds)
    })
  }, [filteredUserIds])

  const handleClearSelected = useCallback(() => {
    setSelectedUserIds([])
  }, [])

  const handleUserToggle = useCallback((userId: number) => {
    setSelectedUserIds((currentUserIds) => {
      if (currentUserIds.includes(userId)) {
        return currentUserIds.filter((currentUserId) => currentUserId !== userId)
      }

      return [...currentUserIds, userId]
    })
  }, [])

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault()

    if (!canSubmit) {
      if (selectedUserIds.length === 0) {
        setSubmitError('Выберите хотя бы одного получателя')
      }

      return
    }

    try {
      setIsSubmitting(true)
      setSubmitError(null)

      const schedule = await fleetReportSchedulesService.createSchedule({
        recipientUserIds: selectedUserIds,
        reportFormat,
        sendTime,
        enabled: true,
      })

      await onSuccess?.(schedule)
      onOpenChange(false)
    } catch (error) {
      setSubmitError(
        error instanceof Error
          ? error.message
          : 'Не удалось сохранить рассылку отчета',
      )
    } finally {
      setIsSubmitting(false)
    }
  }

  async function handleDownloadExampleReport() {
    if (isGeneratingReport) return

    const printWindow = reportFormat === 'PDF'
      ? window.open('', '_blank')
      : null

    try {
      setIsGeneratingReport(true)
      setSubmitError(null)

      const report = await fleetReportService.generateDailyReport(reportFormat)

      if (report.delivery === 'print') {
        if (!report.html || !printWindow) {
          throw new Error('Не удалось открыть печатную версию отчета')
        }

        printWindow.document.open()
        printWindow.document.write(report.html)
        printWindow.document.close()
        printWindow.focus()

        window.setTimeout(() => {
          printWindow.print()
        }, 350)

        return
      }

      if (!report.blob) {
        throw new Error('Не удалось сформировать файл отчета')
      }

      const url = window.URL.createObjectURL(report.blob)
      const link = document.createElement('a')

      link.href = url
      link.download = report.fileName
      document.body.append(link)
      link.click()
      link.remove()
      window.URL.revokeObjectURL(url)
    } catch (error) {
      printWindow?.close()
      setSubmitError(
        error instanceof Error
          ? error.message
          : 'Не удалось сформировать отчет',
      )
    } finally {
      setIsGeneratingReport(false)
    }
  }

  return (
    <Dialog.Root open={open} onOpenChange={onOpenChange}>
      <MotionDialogContent
        open={open}
        overlayClassName="fleet-report-modal__overlay"
        contentClassName="fleet-report-modal"
        motionPreset="fade"
      >
        <div className="fleet-report-modal__header">
          <div>
            <Dialog.Title className="fleet-report-modal__title">
              Рассылка дневного отчета
            </Dialog.Title>

            <Dialog.Description className="fleet-report-modal__description">
              Отчет по парку АТТ за предыдущий день будет отправляться выбранным пользователям.
            </Dialog.Description>
          </div>

          <Dialog.Close
            className="fleet-report-modal__close"
            type="button"
            disabled={isSubmitting}
          >
            <X size={20} />
          </Dialog.Close>
        </div>

        <form className="fleet-report-form" onSubmit={handleSubmit}>
          <div className="fleet-report-layout">
            <section className="fleet-report-section fleet-report-section--recipients">
              <div className="fleet-report-section__header">
                <div>
                  <h3>Получатели</h3>
                  <p>Выберите пользователей, которым нужно отправлять отчет.</p>
                </div>

                <span>{selectedUserIds.length}</span>
              </div>

              <label className="fleet-report-search">
                <Search size={16} />
                <input
                  value={recipientSearch}
                  onChange={(event) => setRecipientSearch(event.target.value)}
                  placeholder="Поиск по ФИО или email"
                  disabled={usersLoading || isSubmitting}
                />
              </label>

              <div className="fleet-report-recipient-actions">
                <button
                  type="button"
                  onClick={handleSelectAllFiltered}
                  disabled={
                    usersLoading ||
                    isSubmitting ||
                    filteredUserIds.length === 0 ||
                    areAllFilteredUsersSelected
                  }
                >
                  Выбрать всех
                </button>

                <button
                  type="button"
                  onClick={handleClearSelected}
                  disabled={isSubmitting || selectedUserIds.length === 0}
                >
                  Снять выбор
                </button>
              </div>

              <div className="fleet-report-recipient-list">
                {usersLoading && (
                  <div className="fleet-report-recipient-state">
                    Загрузка пользователей...
                  </div>
                )}

                {!usersLoading && usersError && (
                  <div className="fleet-report-recipient-state is-error">
                    {usersError}
                  </div>
                )}

                {!usersLoading && !usersError && filteredUsers.length === 0 && (
                  <div className="fleet-report-recipient-state">
                    Пользователи не найдены
                  </div>
                )}

                {!usersLoading && !usersError && filteredUsers.map((user) => {
                  const isSelected = selectedUserIdsSet.has(user.id)
                  const login = user.login ?? user.username ?? ''

                  return (
                    <label
                      className={`fleet-report-recipient ${
                        isSelected ? 'is-selected' : ''
                      }`}
                      key={user.id}
                    >
                      <input
                        type="checkbox"
                        checked={isSelected}
                        disabled={isSubmitting}
                        onChange={() => handleUserToggle(user.id)}
                      />

                      <span className="fleet-report-recipient__avatar">
                        {user.avatarUrl ? (
                          <img src={user.avatarUrl} alt={getEmployeeFullName(user)} />
                        ) : (
                          getUserInitials(user)
                        )}
                      </span>

                      <span className="fleet-report-recipient__info">
                        <strong>
                          {getEmployeeFullName(user) || 'ФИО не указано'}
                        </strong>
                        <small>
                          {user.email || 'Email не указан'}
                          {login ? ` · @${login}` : ''}
                        </small>
                      </span>

                      <span className="fleet-report-recipient__role">
                        {getEmployeeRoleLabel(user.role)}
                      </span>

                      <span className="fleet-report-recipient__check">
                        <Check size={15} />
                      </span>
                    </label>
                  )
                })}
              </div>
            </section>

            <section className="fleet-report-section fleet-report-section--settings">
              <div className="fleet-report-section__header">
                <div>
                  <h3>Параметры отчета</h3>
                  <p>Пока настраиваем только расписание. Файл сформирует backend.</p>
                </div>
              </div>

              <div className="fleet-report-settings">
                <div className="fleet-report-setting">
                  <span>Формат</span>

                  <div className="fleet-report-format" role="radiogroup">
                    {reportFormatOptions.map((option) => {
                      const isSelected = reportFormat === option.value
                      const Icon = option.value === 'PDF' ? FileText : FileSpreadsheet

                      return (
                        <button
                          className={isSelected ? 'is-selected' : ''}
                          type="button"
                          role="radio"
                          aria-checked={isSelected}
                          key={option.value}
                          disabled={isSubmitting}
                          onClick={() => setReportFormat(option.value)}
                        >
                          <Icon size={18} />
                          <span>
                            <b>{option.label}</b>
                          </span>
                        </button>
                      )
                    })}
                  </div>
                </div>

                <label className="fleet-report-setting">
                  <span>Время отправки</span>

                  <div className="fleet-report-time">
                    <Clock3 size={17} />
                    <input
                      type="time"
                      value={sendTime}
                      disabled={isSubmitting}
                      onChange={(event) => setSendTime(event.target.value)}
                      required
                    />
                  </div>
                </label>

                <div className="fleet-report-period">
                  <FileText size={18} />
                  <div>
                    <span>Период отчета</span>
                    <b>За предыдущий календарный день</b>
                  </div>
                </div>

                <div className="fleet-report-period">
                  <UsersRound size={18} />
                  <div>
                    <span>Получателей</span>
                    <b>{selectedUsers.length}</b>
                  </div>
                </div>

                <button
                  className="fleet-report-download"
                  type="button"
                  disabled={isGeneratingReport || isSubmitting}
                  onClick={handleDownloadExampleReport}
                >
                  <Download size={17} />
                  {isGeneratingReport ? 'Формирование...' : 'Скачать пример отчета'}
                </button>
              </div>
            </section>
          </div>

          {submitError && (
            <div className="fleet-report-submit-error">
              {submitError}
            </div>
          )}

          <div className="fleet-report-modal__footer">
            <span>
              Выбрано пользователей: {selectedUserIds.length}
            </span>

            <div>
              <Dialog.Close
                className="fleet-report-modal__cancel"
                type="button"
                disabled={isSubmitting}
              >
                Отмена
              </Dialog.Close>

              <button
                className="fleet-report-modal__submit"
                type="submit"
                disabled={!canSubmit}
              >
                {isSubmitting ? 'Сохранение...' : 'Сохранить рассылку'}
              </button>
            </div>
          </div>
        </form>
      </MotionDialogContent>
    </Dialog.Root>
  )
}
