package collector

import (
	"git.mchus.pro/mchus/logpile/internal/collector/redfishprofile"
	"git.mchus.pro/mchus/logpile/internal/models"
)

func (r redfishSnapshotReader) collectStorage(systemPath string, plan redfishprofile.ResolvedAnalysisPlan) []models.Storage {
	var out []models.Storage
	storageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/Storage"))
	for _, member := range storageMembers {
		if driveCollection, ok := member["Drives"].(map[string]interface{}); ok {
			if driveCollectionPath := asString(driveCollection["@odata.id"]); driveCollectionPath != "" {
				driveDocs, err := r.getCollectionMembers(driveCollectionPath)
				if err == nil {
					for _, driveDoc := range driveDocs {
						if !isAbsentDriveDoc(driveDoc) && !isVirtualStorageDrive(driveDoc) {
							supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
							out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
						}
					}
					if len(driveDocs) == 0 {
						for _, driveDoc := range r.probeDirectDiskBayChildren(driveCollectionPath) {
							if isAbsentDriveDoc(driveDoc) {
								continue
							}
							supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
							out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
						}
					}
				}
				continue
			}
		}
		if drives, ok := member["Drives"].([]interface{}); ok {
			for _, driveAny := range drives {
				driveRef, ok := driveAny.(map[string]interface{})
				if !ok {
					continue
				}
				odata := asString(driveRef["@odata.id"])
				if odata == "" {
					continue
				}
				driveDoc, err := r.getJSON(odata)
				if err != nil {
					continue
				}
				if !isAbsentDriveDoc(driveDoc) && !isVirtualStorageDrive(driveDoc) {
					supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
					out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
				}
			}
			continue
		}
		if looksLikeDrive(member) {
			if isAbsentDriveDoc(member) || isVirtualStorageDrive(member) {
				continue
			}
			supplementalDocs := r.getLinkedSupplementalDocs(member, "DriveMetrics", "EnvironmentMetrics", "Metrics")
			out = append(out, parseDriveWithSupplementalDocs(member, supplementalDocs...))
		}

		if plan.Directives.EnableStorageEnclosureRecovery {
			for _, enclosurePath := range redfishLinkRefs(member, "Links", "Enclosures") {
				driveDocs, err := r.getCollectionMembers(joinPath(enclosurePath, "/Drives"))
				if err == nil {
					for _, driveDoc := range driveDocs {
						if looksLikeDrive(driveDoc) && !isAbsentDriveDoc(driveDoc) && !isVirtualStorageDrive(driveDoc) {
							supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
							out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
						}
					}
					if len(driveDocs) == 0 {
						for _, driveDoc := range r.probeDirectDiskBayChildren(joinPath(enclosurePath, "/Drives")) {
							if isAbsentDriveDoc(driveDoc) || isVirtualStorageDrive(driveDoc) {
								continue
							}
							out = append(out, parseDrive(driveDoc))
						}
					}
				}
			}
		}
	}

	if len(plan.KnownStorageDriveCollections) > 0 {
		for _, driveDoc := range r.collectKnownStorageMembers(systemPath, plan.KnownStorageDriveCollections) {
			if looksLikeDrive(driveDoc) && !isAbsentDriveDoc(driveDoc) && !isVirtualStorageDrive(driveDoc) {
				supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
				out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
			}
		}
	}

	simpleStorageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/SimpleStorage"))
	for _, member := range simpleStorageMembers {
		devices, ok := member["Devices"].([]interface{})
		if !ok {
			continue
		}
		for _, devAny := range devices {
			devDoc, ok := devAny.(map[string]interface{})
			if !ok || !looksLikeDrive(devDoc) || isAbsentDriveDoc(devDoc) || isVirtualStorageDrive(devDoc) {
				continue
			}
			out = append(out, parseDrive(devDoc))
		}
	}

	chassisPaths := r.discoverMemberPaths("/redfish/v1/Chassis", "/redfish/v1/Chassis/1")
	for _, chassisPath := range chassisPaths {
		driveDocs, err := r.getCollectionMembers(joinPath(chassisPath, "/Drives"))
		if err != nil {
			continue
		}
		for _, driveDoc := range driveDocs {
			if !looksLikeDrive(driveDoc) || isAbsentDriveDoc(driveDoc) || isVirtualStorageDrive(driveDoc) {
				continue
			}
			out = append(out, parseDrive(driveDoc))
		}
	}
	if plan.Directives.EnableSupermicroNVMeBackplane {
		for _, chassisPath := range chassisPaths {
			if !isSupermicroNVMeBackplanePath(chassisPath) {
				continue
			}
			for _, driveDoc := range r.probeSupermicroNVMeDiskBays(chassisPath) {
				if !looksLikeDrive(driveDoc) || isAbsentDriveDoc(driveDoc) || isVirtualStorageDrive(driveDoc) {
					continue
				}
				out = append(out, parseDrive(driveDoc))
			}
		}
	}
	return dedupeStorage(out)
}

func (r redfishSnapshotReader) collectStorageVolumes(systemPath string, plan redfishprofile.ResolvedAnalysisPlan) []models.StorageVolume {
	var out []models.StorageVolume
	storageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/Storage"))
	for _, member := range storageMembers {
		controller := firstNonEmpty(asString(member["Id"]), asString(member["Name"]))
		volumeCollectionPath := redfishLinkedPath(member, "Volumes")
		if volumeCollectionPath == "" {
			continue
		}
		volumeDocs, err := r.getCollectionMembers(volumeCollectionPath)
		if err != nil {
			continue
		}
		for _, volDoc := range volumeDocs {
			if looksLikeVolume(volDoc) {
				out = append(out, parseStorageVolume(volDoc, controller))
			}
		}
	}
	if len(plan.KnownStorageVolumeCollections) > 0 {
		for _, volDoc := range r.collectKnownStorageMembers(systemPath, plan.KnownStorageVolumeCollections) {
			if looksLikeVolume(volDoc) {
				out = append(out, parseStorageVolume(volDoc, storageControllerFromPath(asString(volDoc["@odata.id"]))))
			}
		}
	}
	return dedupeStorageVolumes(out)
}
