package linuxmodules

import (
	"fmt"
	"rubric/utils"
)

var DisksModule = Module{
	Key:         "disks",
	Aliases:     []string{"d", "lvm", "raid", "диски"},
	Title:       "Диски, файловые системы, LVM и RAID",
	Description: "Темы 22–26: разделы, mount, LVM, программный RAID",
	Run:         showDisks,
}

func showDisks() {
	utils.Header("Linux — Диски, файловые системы, LVM и RAID")

	// ─── 22. Работа с дисками ─────────────────────────────────────
	utils.Section("22. Работа с дисками и разделами")

	utils.Println(utils.ColorBold + "Именование устройств:" + utils.ColorReset)
	utils.Code(`/dev/sda      — первый SATA/SCSI диск
/dev/sdb      — второй диск
/dev/sda1     — первый раздел первого диска
/dev/sda2     — второй раздел первого диска
/dev/nvme0n1  — первый NVMe диск
/dev/nvme0n1p1 — первый раздел NVMe диска
/dev/vda      — виртуальный диск (KVM/QEMU)
/dev/xvda     — диск Xen
/dev/loop0    — loop-устройство (ISO-образ)`)

	utils.Println(utils.ColorBold + "Просмотр дисков и разделов:" + utils.ColorReset)
	utils.Command("lsblk", "дерево блочных устройств")
	utils.Command("lsblk -f", "с типом ФС и UUID")
	utils.Command("lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE", "выбрать столбцы")
	utils.Command("fdisk -l", "все диски и разделы (root)")
	utils.Command("fdisk -l /dev/sda", "разделы диска sda")
	utils.Command("parted -l", "таблицы разделов (GPT и MBR)")
	utils.Command("blkid", "UUID и типы ФС всех устройств")
	utils.Command("blkid /dev/sda1", "UUID конкретного раздела")
	fmt.Println()
	utils.Println(utils.ColorBold + "Разбивка диска (fdisk):" + utils.ColorReset)
	utils.Code(`sudo fdisk /dev/sdb    # интерактивная работа с разделами

Команды fdisk:
  p — показать таблицу разделов
  n — новый раздел
  d — удалить раздел
  t — изменить тип раздела
  l — список типов разделов
  w — записать изменения (опасно!)
  q — выйти без сохранения

# Для GPT-дисков и дисков > 2ТБ — используйте parted или gdisk`)

	utils.Println(utils.ColorBold + "Создание файловой системы (mkfs):" + utils.ColorReset)
	utils.Command("mkfs.ext4 /dev/sdb1", "создать ext4")
	utils.Command("mkfs.xfs /dev/sdb1", "создать xfs")
	utils.Command("mkfs.ext4 -L data /dev/sdb1", "с меткой 'data'")
	utils.Command("mkswap /dev/sdb2", "создать swap")
	utils.Command("swapon /dev/sdb2", "активировать swap")
	utils.Command("swapon -s", "показать активные swap")
	utils.Command("swapoff /dev/sdb2", "отключить swap")
	fmt.Println()
	utils.Println(utils.ColorBold + "Проверка и восстановление ФС:" + utils.ColorReset)
	utils.Command("fsck /dev/sdb1", "проверить ФС (только при размонтированной!)")
	utils.Command("fsck -n /dev/sdb1", "только проверить, не исправлять")
	utils.Command("e2fsck -f /dev/sdb1", "принудительная проверка ext2/3/4")
	utils.Command("xfs_repair /dev/sdb1", "восстановление XFS")

	utils.Println(utils.ColorBold + "Использование диска:" + utils.ColorReset)
	utils.Command("df -h", "занятое и свободное место на ФС")
	utils.Command("df -hT", "с типом ФС")
	utils.Command("du -sh /var/log", "размер директории")
	utils.Command("du -sh /*", "размер каждой директории в корне")
	utils.Command("du -sh * | sort -h", "отсортировать по размеру")
	utils.Command("ncdu /var", "интерактивный анализ (нужно установить)")

	// ─── 23–24. Файловые системы и монтирование ───────────────────
	utils.Section("23–24. Файловые системы и монтирование")

	utils.Println(utils.ColorBold + "mount — монтирование:" + utils.ColorReset)
	utils.Command("mount", "список всех смонтированных ФС")
	utils.Command("mount /dev/sdb1 /mnt/data", "монтировать раздел")
	utils.Command("mount -t ext4 /dev/sdb1 /mnt", "указать тип ФС")
	utils.Command("mount -o ro /dev/sdb1 /mnt", "только чтение")
	utils.Command("mount -o remount,rw /", "перемонтировать с правами записи")
	utils.Command("mount UUID=abc123 /mnt/data", "монтировать по UUID")
	utils.Command("mount -a", "смонтировать всё из /etc/fstab")
	utils.Command("umount /mnt/data", "размонтировать")
	utils.Command("umount -l /mnt/data", "ленивое размонтирование (когда занято)")
	utils.Command("lsof /mnt/data", "кто использует раздел (если umount отказывает)")
	fmt.Println()
	utils.Println(utils.ColorBold + "/etc/fstab — автомонтирование при старте:" + utils.ColorReset)
	utils.Code(`# Формат: устройство  точка_монтирования  тип  опции  dump  fsck
UUID=abc123  /mnt/data  ext4  defaults  0  2
/dev/sdb1    /mnt/data  xfs   defaults  0  0
//server/share /mnt/smb cifs credentials=/etc/samba.creds 0 0
tmpfs        /tmp       tmpfs defaults,size=2G 0 0

# Опции монтирования:
defaults     — rw, suid, exec, auto, nouser, async
ro           — только чтение
rw           — чтение и запись
noexec       — запрет запуска файлов
nosuid       — игнорировать SUID/SGID биты
noatime      — не обновлять atime (быстрее)
auto         — монтировать при mount -a
noauto       — не монтировать автоматически

# Столбцы dump и fsck:
# dump: 0 = не бэкапить, 1 = бэкапить
# fsck: 0 = не проверять, 1 = / (первый), 2 = остальные`)

	utils.Note("Всегда используйте UUID вместо /dev/sdb1 в fstab — имена устройств могут меняться после перезагрузки.")

	// ─── 25. LVM ──────────────────────────────────────────────────
	utils.Section("25. Управление логическими томами — LVM")

	utils.Println("LVM позволяет гибко управлять дисковым пространством:")
	utils.Println("объединять несколько дисков, изменять размер томов без перезагрузки.")
	fmt.Println()
	utils.Code(`Структура LVM:
PV (Physical Volume) — физический диск или раздел (/dev/sdb)
VG (Volume Group)    — группа PV, единый пул пространства
LV (Logical Volume)  — логический том из VG (аналог раздела)

PV: /dev/sdb  /dev/sdc
         ↓         ↓
    VG: vg_data (объединённое пространство)
         ↓
    LV: /dev/vg_data/lv_web  /dev/vg_data/lv_db`)

	utils.Println(utils.ColorBold + "Создание LVM:" + utils.ColorReset)
	utils.Code(`# 1. Создать Physical Volume:
pvcreate /dev/sdb /dev/sdc
pvs           # показать PV
pvdisplay     # подробно

# 2. Создать Volume Group:
vgcreate vg_data /dev/sdb /dev/sdc
vgs           # показать VG
vgdisplay vg_data

# 3. Создать Logical Volume:
lvcreate -L 20G -n lv_web vg_data    # 20 ГБ
lvcreate -l 100%FREE -n lv_db vg_data  # всё свободное
lvs           # показать LV
lvdisplay /dev/vg_data/lv_web

# 4. Создать ФС и смонтировать:
mkfs.ext4 /dev/vg_data/lv_web
mount /dev/vg_data/lv_web /var/www`)

	utils.Println(utils.ColorBold + "Расширение LV:" + utils.ColorReset)
	utils.Code(`# Расширить LV на 10 ГБ:
lvextend -L +10G /dev/vg_data/lv_web

# Расширить ФС (ext4):
resize2fs /dev/vg_data/lv_web

# Одной командой (ext4):
lvextend -L +10G -r /dev/vg_data/lv_web   # -r = resize ФС

# Для XFS (только увеличение):
xfs_growfs /var/www`)

	utils.Println(utils.ColorBold + "Добавить диск в VG:" + utils.ColorReset)
	utils.Code(`pvcreate /dev/sdd
vgextend vg_data /dev/sdd`)

	// ─── 26. Программный RAID ─────────────────────────────────────
	utils.Section("26. Программный RAID — MD (mdadm)")

	utils.Println("RAID — избыточный массив для надёжности и/или производительности.")
	fmt.Println()
	utils.Code(`Уровни RAID:
RAID 0  — страйпинг (производительность), без избыточности
RAID 1  — зеркало (надёжность), нужно 2 диска, использует 50%
RAID 5  — страйп + чётность, нужно 3+ дисков, теряем 1 диск
RAID 6  — двойная чётность, нужно 4+ дисков, теряем 2 диска
RAID 10 — зеркало + страйп, нужно 4 диска, теряем до N/2`)

	utils.Println(utils.ColorBold + "mdadm — управление программным RAID:" + utils.ColorReset)
	utils.Code(`# Создать RAID 1 из двух дисков:
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb /dev/sdc

# Создать RAID 5:
mdadm --create /dev/md0 --level=5 --raid-devices=3 \
  /dev/sdb /dev/sdc /dev/sdd

# Состояние массива:
cat /proc/mdstat           # текущее состояние
mdadm --detail /dev/md0    # подробная информация

# Сохранить конфигурацию:
mdadm --detail --scan >> /etc/mdadm/mdadm.conf

# Добавить запасной диск:
mdadm /dev/md0 --add /dev/sde

# Удалить диск из массива:
mdadm /dev/md0 --fail /dev/sdb
mdadm /dev/md0 --remove /dev/sdb

# Остановить массив:
mdadm --stop /dev/md0`)

	utils.Footer()
}
