package de.danoeh.antennapod.parser.transcript;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.internal.StringUtil;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import de.danoeh.antennapod.model.feed.Transcript;
import de.danoeh.antennapod.model.feed.TranscriptSegment;

public class SrtTranscriptParser {
    private static final Pattern TIMECODE_PATTERN = Pattern.compile("^([0-9]{2}):([0-9]{2}):([0-9]{2}),([0-9]{3})$");

    public static Transcript parse(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        str = str.replaceAll("\r\n", "\n");

        Transcript transcript = new Transcript();
        List<String> lines = Arrays.asList(str.split("\n"));
        Iterator<String> iter = lines.iterator();
        String speaker = "";
        String prevSpeaker = "";
        StringBuilder body;
        String line;
        String segmentBody = "";
        long startTimecode = -1L;
        long spanStartTimecode = -1L;
        long spanEndTimecode = -1L;
        long endTimecode = -1L;
        long duration = 0L;
        Set<String> speakers = new HashSet<>();

        while (iter.hasNext()) {
            body = new StringBuilder();
            line = iter.next();

            if (line.isEmpty()) {
                continue;
            }

            spanEndTimecode = endTimecode;
            if (line.contains("-->")) {
                String[] timecodes = line.split("-->");
                if (timecodes.length < 2) {
                    continue;
                }
                startTimecode = parseTimecode(timecodes[0].trim());
                endTimecode = parseTimecode(timecodes[1].trim());
                if (startTimecode == -1 || endTimecode == -1) {
                    continue;
                }

                if (spanStartTimecode == -1) {
                    spanStartTimecode = startTimecode;
                }
                duration += endTimecode - startTimecode;
                do {
                    line = iter.next();
                    if (StringUtil.isBlank(line)) {
                        break;
                    }
                    body.append(line.strip());
                    body.append(" ");
                } while (iter.hasNext());
            }

            if (body.indexOf(": ") != -1) {
                String[] parts = body.toString().trim().split(":");
                if (parts.length < 2) {
                    continue;
                }
                prevSpeaker = speaker;
                speaker = parts[0];
                speakers.add(speaker);
                body = new StringBuilder(parts[1].strip());
                if (StringUtils.isNotEmpty(prevSpeaker) && !StringUtils.equals(speaker, prevSpeaker)) {
                    if (StringUtils.isNotEmpty(segmentBody)) {
                        transcript.addSegment(new TranscriptSegment(spanStartTimecode,
                                spanEndTimecode, segmentBody, prevSpeaker));
                        duration = 0L;
                        spanStartTimecode = startTimecode;
                        segmentBody = body.toString();
                        continue;
                    }
                }
            } else {
                if (StringUtils.isNotEmpty(prevSpeaker) && StringUtils.isEmpty(speaker)) {
                    speaker = prevSpeaker;
                }
            }

            segmentBody += " " + body;
            segmentBody = StringUtils.trim(segmentBody);
            if (duration >= TranscriptParser.MIN_SPAN && endTimecode > spanStartTimecode) {
                transcript.addSegment(new TranscriptSegment(spanStartTimecode, endTimecode, segmentBody, speaker));
                duration = 0L;
                spanStartTimecode = -1L;
                segmentBody = "";
            }
        }

        if (!StringUtil.isBlank(segmentBody) && endTimecode > spanStartTimecode) {
            segmentBody = StringUtils.trim(segmentBody);
            transcript.addSegment(new TranscriptSegment(spanStartTimecode, endTimecode, segmentBody, speaker));
        }
        if (transcript.getSegmentCount() > 0) {
            transcript.setSpeakers(speakers);
            return transcript;
        } else {
            return null;
        }
    }

    static long parseTimecode(String timecode) {
        Matcher matcher = TIMECODE_PATTERN.matcher(timecode);
        if (!matcher.matches()) {
            return -1;
        }
        long hours = Integer.parseInt(matcher.group(1));
        long minutes = Integer.parseInt(matcher.group(2));
        long seconds = Integer.parseInt(matcher.group(3));
        long milliseconds = Integer.parseInt(matcher.group(4));
        return (hours * 60 * 60 * 1000) + (minutes * 60 * 1000) + (seconds * 1000) + milliseconds;
    }
}
