package com.elphel.imagej.ims;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashSet;

public class DjiSrtReader {
	private final String pathSpec;
	private final ArrayList<String> sourceFiles = new ArrayList<String>();
	private UasLogRecord[] rec_arr = null;
	private double firstEpochSeconds = Double.NaN;
	private double lastEpochSeconds = Double.NaN;

	private static class SrtRow {
		double epochSeconds;
		double latitude;
		double longitude;
		double relAlt;
	}

	public DjiSrtReader(String path) {
		this.pathSpec = path;
		load();
	}

	public UasLogRecord[] getRecords() {
		return rec_arr;
	}

	public double getFirstEpochSeconds() {
		return firstEpochSeconds;
	}

	public double getLastEpochSeconds() {
		return lastEpochSeconds;
	}

	public String[] getSourceFiles() {
		return sourceFiles.toArray(new String[0]);
	}

	public String getPathSpec() {
		return pathSpec;
	}

	public static boolean looksLikeSrtPath(String path) {
		if (path == null) {
			return false;
		}
		String lower = path.toLowerCase();
		try {
			if (Files.isDirectory(Paths.get(path))) {
				return true;
			}
		} catch (RuntimeException e) {
			// ignore malformed paths and continue pattern-based checks
		}
		return lower.contains(".srt")
				|| lower.contains("*.srt")
				|| lower.contains("?")
				|| lower.contains("*")
				|| lower.contains(";")
				|| lower.contains(",");
	}

	private void load() {
		ArrayList<Path> files = resolveSrtPaths(pathSpec);
		if (files.isEmpty()) {
			throw new IllegalArgumentException("No DJI SRT files found for path: " + pathSpec);
		}
		ArrayList<SrtRow> rows = new ArrayList<SrtRow>();
		for (Path filePath : files) {
			ArrayList<DjiSrt> parsed = DjiSrt.parseDjiSrt(filePath.toString());
			if ((parsed == null) || parsed.isEmpty()) {
				continue;
			}
			sourceFiles.add(filePath.toString());
			for (DjiSrt djiSrt : parsed) {
				if (djiSrt.date == null) {
					continue;
				}
				if (Double.isNaN(djiSrt.latitude) || Double.isNaN(djiSrt.longitude)) {
					continue;
				}
				SrtRow row = new SrtRow();
				row.epochSeconds = djiSrt.date.getTime() * 1.0E-3;
				row.latitude = djiSrt.latitude;
				row.longitude = djiSrt.longitude;
				row.relAlt = Double.isNaN(djiSrt.rel_alt) ? 0.0 : djiSrt.rel_alt;
				rows.add(row);
			}
		}
		if (rows.isEmpty()) {
			throw new IllegalArgumentException("No valid DJI SRT records found for path: " + pathSpec);
		}
		rows.sort(new Comparator<SrtRow>() {
			@Override
			public int compare(SrtRow lhs, SrtRow rhs) {
				return (lhs.epochSeconds > rhs.epochSeconds) ? 1 : (lhs.epochSeconds < rhs.epochSeconds) ? -1 : 0;
			}
		});
		firstEpochSeconds = rows.get(0).epochSeconds;
		lastEpochSeconds = rows.get(rows.size() - 1).epochSeconds;
		double homeLat = rows.get(0).latitude;
		double homeLon = rows.get(0).longitude;
		ArrayList<UasLogRecord> recList = new ArrayList<UasLogRecord>(rows.size());
		for (SrtRow row : rows) {
			double[] ned = Imx5.nedFromLla(
					new double[] {row.latitude, row.longitude, row.relAlt},
					new double[] {homeLat, homeLon, 0.0});
			double distance = Math.sqrt(ned[0] * ned[0] + ned[1] * ned[1] + ned[2] * ned[2]);
			double relTs = row.epochSeconds - firstEpochSeconds;
			recList.add(new UasLogRecord(
					relTs,
					distance,
					row.latitude,
					row.longitude,
					row.relAlt,
					homeLat,
					homeLon));
		}
		rec_arr = UasLogRecord.getArray(recList);
		UasLogRecord.fillUndefined(rec_arr);
		System.out.println("DjiSrtReader: loaded " + rec_arr.length + " records from " + sourceFiles.size() + " file(s)");
	}

	private static ArrayList<Path> resolveSrtPaths(String pathSpec) {
		ArrayList<Path> files = new ArrayList<Path>();
		if (pathSpec == null) {
			return files;
		}
		String[] tokens = splitPathSpec(pathSpec);
		LinkedHashSet<String> unique = new LinkedHashSet<String>();
		for (String token : tokens) {
			if (token == null) {
				continue;
			}
			String trimmed = token.trim();
			if (trimmed.isEmpty()) {
				continue;
			}
			collectPaths(trimmed, unique);
		}
		for (String s : unique) {
			files.add(Paths.get(s));
		}
		files.sort(new Comparator<Path>() {
			@Override
			public int compare(Path lhs, Path rhs) {
				return lhs.toString().compareTo(rhs.toString());
			}
		});
		return files;
	}

	private static String[] splitPathSpec(String pathSpec) {
		if ((pathSpec.indexOf(',') < 0) && (pathSpec.indexOf(';') < 0) && (pathSpec.indexOf('\n') < 0)) {
			return new String[] {pathSpec};
		}
		return pathSpec.split("[,;\\n]+");
	}

	private static boolean hasWildcard(String path) {
		return (path.indexOf('*') >= 0) || (path.indexOf('?') >= 0);
	}

	private static void collectPaths(String token, LinkedHashSet<String> unique) {
		Path path = Paths.get(token);
		if (Files.isDirectory(path)) {
			addDirectorySrt(path, unique);
			return;
		}
		if (hasWildcard(token)) {
			Path dir = path.getParent();
			if (dir == null) {
				dir = Paths.get(".");
			}
			String pattern = path.getFileName().toString();
			addDirectoryPattern(dir, pattern, unique);
			return;
		}
		if (Files.isRegularFile(path) && path.toString().toLowerCase().endsWith(".srt")) {
			unique.add(path.toAbsolutePath().normalize().toString());
		}
	}

	private static void addDirectorySrt(Path dir, LinkedHashSet<String> unique) {
		addDirectoryPattern(dir, "*.srt", unique);
		addDirectoryPattern(dir, "*.SRT", unique);
	}

	private static void addDirectoryPattern(Path dir, String glob, LinkedHashSet<String> unique) {
		if (!Files.isDirectory(dir)) {
			return;
		}
		try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, glob)) {
			for (Path p : stream) {
				if (Files.isRegularFile(p) && p.toString().toLowerCase().endsWith(".srt")) {
					unique.add(p.toAbsolutePath().normalize().toString());
				}
			}
		} catch (IOException e) {
			System.err.println("DjiSrtReader: failed to list " + dir + " (" + glob + "): " + e.getMessage());
		}
	}
}
