import { machineAnalyticsService } from '../../machine/api/machineAnalyticsService'
import { machinesService } from '../../machine/api/machinesService'
import type {
  Machine,
  MachineStateCode,
  MachineTelemetryInterval,
  MachineUsageSummary,
} from '../../machine/model/types'
import type {
  FleetDailyReport,
  FleetDailyReportHistoryRow,
  FleetDailyReportMachineRow,
  FleetReportFormat,
  GeneratedFleetReport,
} from '../model/types'

const dayMs = 24 * 60 * 60 * 1000

function getStateLabel(state: MachineStateCode) {
  if (state === 'IDLE') return 'Стоит'
  if (state === 'ENGINE_ON') return 'Заведена'
  if (state === 'MOVING') return 'В движении'
  if (state === 'NO_DATA') return 'Нет данных'

  return state
}

function formatDate(date: string | number | Date) {
  return new Intl.DateTimeFormat('ru-RU', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  }).format(new Date(date))
}

function formatDateTime(date?: string | number | null) {
  if (!date) return 'Нет данных'

  return new Intl.DateTimeFormat('ru-RU', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  }).format(new Date(date))
}

function formatDuration(totalSeconds: number) {
  const normalizedSeconds = Math.max(0, Math.floor(totalSeconds))
  const totalMinutes = Math.floor(normalizedSeconds / 60)
  const hours = Math.floor(totalMinutes / 60)
  const minutes = totalMinutes % 60

  if (hours > 0) return `${hours} ч ${minutes} мин`
  if (totalMinutes > 0) return `${totalMinutes} мин`

  return `${normalizedSeconds} сек`
}

function formatPercent(value: number) {
  return `${Math.round(value)}%`
}

function escapeHtml(value: string | number | null | undefined) {
  return String(value ?? '')
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#39;')
}

function normalizeDateValue(date: Date) {
  return date.toISOString().slice(0, 10)
}

function getDayRange(dateValue: string) {
  const start = new Date(`${dateValue}T00:00:00.000Z`).getTime()

  return {
    startIso: new Date(start).toISOString(),
    endIso: new Date(start + dayMs).toISOString(),
  }
}

async function getAllMachines() {
  const response = await machinesService.getMachines({
    page: 0,
    pageSize: 1000,
    sortDirection: 'ASC',
    sortField: 'Name',
  })

  return response.page
}

function getFallbackReportDate(machines: Machine[]) {
  const latestDataTimestamp = Math.max(
    0,
    ...machines
      .map((machine) => (
        machine.lastDataReceivedAt
          ? new Date(machine.lastDataReceivedAt).getTime()
          : 0
      )),
  )

  if (latestDataTimestamp > 0) {
    return normalizeDateValue(new Date(latestDataTimestamp))
  }

  return normalizeDateValue(new Date(Date.now() - dayMs))
}

function getMachineRow(
  machine: Machine,
  summary: MachineUsageSummary,
  intervals: MachineTelemetryInterval[],
): FleetDailyReportMachineRow {
  return {
    machineId: machine.id,
    name: machine.name,
    licensePlate: machine.licensePlate,
    type: machine.type,
    department: machine.department,
    beaconBound: Boolean(machine.beaconId),
    lastKnownState: getStateLabel(machine.lastKnownState),
    lastDataReceivedAt: formatDateTime(machine.lastDataReceivedAt),
    movingSeconds: summary.movingSeconds,
    engineOnSeconds: summary.engineOnSeconds,
    idleSeconds: summary.idleSeconds,
    noDataSeconds: summary.noDataSeconds,
    stateChangesCount: intervals.length,
    utilizationPercent: summary.utilizationPercent,
  }
}

function getHistoryRows(
  machine: Machine,
  intervals: MachineTelemetryInterval[],
): FleetDailyReportHistoryRow[] {
  return intervals.map((interval) => ({
    machineId: machine.id,
    machineName: machine.name,
    licensePlate: machine.licensePlate,
    startedAt: formatDateTime(interval.startedAt),
    endedAt: formatDateTime(interval.endedAt),
    state: getStateLabel(interval.state),
    durationSeconds: interval.durationSeconds,
  }))
}

function getReportSummary(
  machines: FleetDailyReportMachineRow[],
): FleetDailyReport['summary'] {
  return machines.reduce(
    (summary, machine) => ({
      totalMachines: summary.totalMachines + 1,
      boundMachines: summary.boundMachines + (machine.beaconBound ? 1 : 0),
      unboundMachines: summary.unboundMachines + (machine.beaconBound ? 0 : 1),
      machinesWithMovement:
        summary.machinesWithMovement + (machine.movingSeconds > 0 ? 1 : 0),
      machinesWithoutData:
        summary.machinesWithoutData +
        (
          machine.movingSeconds +
          machine.engineOnSeconds +
          machine.idleSeconds === 0
            ? 1
            : 0
        ),
      movingSeconds: summary.movingSeconds + machine.movingSeconds,
      engineOnSeconds: summary.engineOnSeconds + machine.engineOnSeconds,
      idleSeconds: summary.idleSeconds + machine.idleSeconds,
      noDataSeconds: summary.noDataSeconds + machine.noDataSeconds,
      stateChangesCount: summary.stateChangesCount + machine.stateChangesCount,
    }),
    {
      totalMachines: 0,
      boundMachines: 0,
      unboundMachines: 0,
      machinesWithMovement: 0,
      machinesWithoutData: 0,
      movingSeconds: 0,
      engineOnSeconds: 0,
      idleSeconds: 0,
      noDataSeconds: 0,
      stateChangesCount: 0,
    },
  )
}

function renderSummaryTable(report: FleetDailyReport) {
  const rows = [
    ['Дата отчета', formatDate(`${report.date}T00:00:00.000Z`)],
    ['Сформирован', formatDateTime(report.generatedAt)],
    ['Всего АТТ', report.summary.totalMachines],
    ['С маяками', report.summary.boundMachines],
    ['Без маяков', report.summary.unboundMachines],
    ['АТТ в движении', report.summary.machinesWithMovement],
    ['АТТ без данных', report.summary.machinesWithoutData],
    ['В движении', formatDuration(report.summary.movingSeconds)],
    ['Заведена', formatDuration(report.summary.engineOnSeconds)],
    ['Стояла', formatDuration(report.summary.idleSeconds)],
    ['Без данных', formatDuration(report.summary.noDataSeconds)],
    ['Смен состояний', report.summary.stateChangesCount],
  ]

  return `
    <table>
      <tbody>
        ${rows.map((row) => `
          <tr>
            <th>${escapeHtml(row[0])}</th>
            <td>${escapeHtml(row[1])}</td>
          </tr>
        `).join('')}
      </tbody>
    </table>
  `
}

function renderMachineTable(report: FleetDailyReport) {
  return `
    <table>
      <thead>
        <tr>
          <th>АТТ</th>
          <th>Госномер</th>
          <th>Тип</th>
          <th>Подразделение</th>
          <th>Маяк</th>
          <th>Последний статус</th>
          <th>Последние данные</th>
          <th>В движении</th>
          <th>Заведена</th>
          <th>Стояла</th>
          <th>Без данных</th>
          <th>Смен состояний</th>
          <th>КПИ</th>
        </tr>
      </thead>
      <tbody>
        ${report.machines.map((machine) => `
          <tr>
            <td>${escapeHtml(machine.name)}</td>
            <td>${escapeHtml(machine.licensePlate)}</td>
            <td>${escapeHtml(machine.type)}</td>
            <td>${escapeHtml(machine.department)}</td>
            <td>${machine.beaconBound ? 'Привязан' : 'Не привязан'}</td>
            <td>${escapeHtml(machine.lastKnownState)}</td>
            <td>${escapeHtml(machine.lastDataReceivedAt)}</td>
            <td>${escapeHtml(formatDuration(machine.movingSeconds))}</td>
            <td>${escapeHtml(formatDuration(machine.engineOnSeconds))}</td>
            <td>${escapeHtml(formatDuration(machine.idleSeconds))}</td>
            <td>${escapeHtml(formatDuration(machine.noDataSeconds))}</td>
            <td>${machine.stateChangesCount}</td>
            <td>${escapeHtml(formatPercent(machine.utilizationPercent))}</td>
          </tr>
        `).join('')}
      </tbody>
    </table>
  `
}

function renderHistoryTable(report: FleetDailyReport) {
  return `
    <table>
      <thead>
        <tr>
          <th>АТТ</th>
          <th>Госномер</th>
          <th>Начало</th>
          <th>Конец</th>
          <th>Состояние</th>
          <th>Длительность</th>
        </tr>
      </thead>
      <tbody>
        ${report.history.map((item) => `
          <tr>
            <td>${escapeHtml(item.machineName)}</td>
            <td>${escapeHtml(item.licensePlate)}</td>
            <td>${escapeHtml(item.startedAt)}</td>
            <td>${escapeHtml(item.endedAt)}</td>
            <td>${escapeHtml(item.state)}</td>
            <td>${escapeHtml(formatDuration(item.durationSeconds))}</td>
          </tr>
        `).join('')}
      </tbody>
    </table>
  `
}

function renderReportHtml(report: FleetDailyReport, mode: 'excel' | 'print') {
  return `<!doctype html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <title>Отчет по парку АТТ за ${escapeHtml(formatDate(`${report.date}T00:00:00.000Z`))}</title>
        <style>
          body {
            margin: ${mode === 'print' ? '32px' : '0'};
            font-family: Arial, sans-serif;
            color: #111827;
            background: #ffffff;
          }

          h1 {
            margin: 0 0 8px;
            font-size: 22px;
          }

          h2 {
            margin: 24px 0 10px;
            font-size: 16px;
          }

          p {
            margin: 0 0 18px;
            color: #6a768e;
            font-size: 13px;
          }

          table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 18px;
          }

          th,
          td {
            border: 1px solid #dbe2ee;
            padding: 7px 9px;
            font-size: 12px;
            text-align: left;
            vertical-align: top;
          }

          th {
            background: #eef2ff;
            color: #111827;
            font-weight: 700;
          }

          tr:nth-child(even) td {
            background: #f8fafc;
          }

          @media print {
            body {
              margin: 0;
            }

            h1,
            h2 {
              break-after: avoid;
            }
          }
        </style>
      </head>
      <body>
        <h1>Отчет по парку АТТ</h1>
        <p>Период: ${escapeHtml(formatDate(`${report.date}T00:00:00.000Z`))}. Сформирован: ${escapeHtml(formatDateTime(report.generatedAt))}.</p>

        <h2>Сводка</h2>
        ${renderSummaryTable(report)}

        <h2>АТТ</h2>
        ${renderMachineTable(report)}

        <h2>История состояний</h2>
        ${renderHistoryTable(report)}
      </body>
    </html>
  `
}

function getExcelBlob(report: FleetDailyReport) {
  const html = renderReportHtml(report, 'excel')

  return new Blob([html], {
    type: 'application/vnd.ms-excel;charset=utf-8',
  })
}

export const fleetReportService = {
  async getDefaultDailyReportDate(): Promise<string> {
    const machines = await getAllMachines()

    return getFallbackReportDate(machines)
  },

  async buildDailyReport(date?: string): Promise<FleetDailyReport> {
    const machines = await getAllMachines()
    const reportDate = date ?? getFallbackReportDate(machines)
    const range = getDayRange(reportDate)
    const machineRows: FleetDailyReportMachineRow[] = []
    const historyRows: FleetDailyReportHistoryRow[] = []

    for (const machine of machines) {
      const [summary, intervals] = await Promise.all([
        machineAnalyticsService.getMachineUsageSummary(machine.id, 'today', {
          dateFrom: range.startIso,
          dateTo: range.endIso,
        }),
        machineAnalyticsService.getMachineTelemetryIntervals(machine.id, 'today', {
          dateFrom: range.startIso,
          dateTo: range.endIso,
        }),
      ])

      machineRows.push(getMachineRow(machine, summary, intervals))
      historyRows.push(...getHistoryRows(machine, intervals))
    }

    return {
      date: reportDate,
      generatedAt: new Date().toISOString(),
      summary: getReportSummary(machineRows),
      machines: machineRows,
      history: historyRows,
    }
  },

  async generateDailyReport(
    format: FleetReportFormat,
    date?: string,
  ): Promise<GeneratedFleetReport> {
    const report = await this.buildDailyReport(date)

    if (format === 'PDF') {
      return {
        fileName: `fleet-att-daily-report-${report.date}.pdf`,
        mimeType: 'text/html;charset=utf-8',
        delivery: 'print',
        html: renderReportHtml(report, 'print'),
      }
    }

    return {
      fileName: `fleet-att-daily-report-${report.date}.xls`,
      mimeType: 'application/vnd.ms-excel;charset=utf-8',
      delivery: 'download',
      blob: getExcelBlob(report),
    }
  },
}

