package ctbrec;

import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.PlaylistException;

import ctbrec.event.EventBusHolder;
import ctbrec.event.RecordingStateChangedEvent;
import ctbrec.recorder.download.Download;

public class Recording {
    private Model model;
    private transient Download download;
    private Instant startDate;
    private String path;
    private State status = State.UNKNOWN;
    private int progress = -1;
    private long sizeInByte = -1;
    private String metaDataFile;

    public static enum State {
        RECORDING("recording"),
        GENERATING_PLAYLIST("generating playlist"),
        POST_PROCESSING("post-processing"),
        FINISHED("finished"),
        DOWNLOADING("downloading"),
        DELETING("deleting"),
        DELETED("deleted"),
        UNKNOWN("unknown"),
        WAITING("waiting"),
        FAILED("failed");

        private String desc;

        State(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return desc;
        }
    }

    public Recording() {}

    public Instant getStartDate() {
        return startDate;
    }

    public void setStartDate(Instant startDate) {
        this.startDate = startDate;
    }

    public State getStatus() {
        return status;
    }

    public void setStatus(State status) {
        this.status = status;
    }

    public void setStatusWithEvent(State status, boolean fireEvent) {
        setStatus(status);
        fireStatusEvent(status);
    }

    public int getProgress() {
        return this.progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public File getAbsoluteFile() {
        String recordingsDir = Config.getInstance().getSettings().recordingsDir;
        File recordingsFile = new File(recordingsDir, getPath());
        return recordingsFile;
    }

    public long getSizeInByte() {
        return sizeInByte;
    }

    public void setSizeInByte(long sizeInByte) {
        this.sizeInByte = sizeInByte;
    }

    public void postprocess() {
        getDownload().postprocess(this);
    }

    private void fireStatusEvent(State status) {
        RecordingStateChangedEvent evt = new RecordingStateChangedEvent(getDownload().getTarget(), status, getModel(), getStartDate());
        EventBusHolder.BUS.post(evt);
    }

    public Model getModel() {
        return model;
    }

    public void setModel(Model model) {
        this.model = model;
    }

    public Download getDownload() {
        return download;
    }

    public void setDownload(Download download) {
        this.download = download;
    }

    public String getMetaDataFile() {
        return metaDataFile;
    }

    public void setMetaDataFile(String metaDataFile) {
        this.metaDataFile = metaDataFile;
    }

    public Duration getLength() throws IOException, ParseException, PlaylistException {
        if (getDownload() != null) {
            return getDownload().getLength();
        } else {
            return Duration.ofSeconds(0);
        }
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getStartDate() == null) ? 0 : (int) (getStartDate().toEpochMilli() ^ (getStartDate().toEpochMilli() >>> 32)));
        result = prime * result + ((model == null) ? 0 : model.hashCode());
        result = prime * result + ((path == null) ? 0 : path.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if(!(obj instanceof Recording)) {
            return false;
        }
        Recording other = (Recording) obj;
        if (getModel() == null) {
            if (other.getModel() != null) {
                return false;
            }
        } else if (!getModel().equals(other.getModel())) {
            return false;
        }
        if (getPath() == null) {
            if (other.getPath() != null) {
                return false;
            }
        } else if (!getPath().equals(other.getPath())) {
            return false;
        }
        if (getStartDate() == null) {
            if (other.getStartDate() != null) {
                return false;
            }
        } else if (getStartDate().toEpochMilli() != other.getStartDate().toEpochMilli()) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Config.RECORDING_DATE_FORMAT);
        LocalDateTime localStartDate = LocalDateTime.ofInstant(getStartDate(), ZoneId.systemDefault());
        return getModel().getSanitizedNamed() + '_' + formatter.format(localStartDate);
    }

    private long getSize() {
        File rec = new File(Config.getInstance().getSettings().recordingsDir, getPath());
        if(rec.isDirectory()) {
            long size = 0;
            File[] files = rec.listFiles();
            for (File file : files) {
                size += file.length();
            }
            return size;
        } else {
            return rec.length();
        }
    }

    public void refresh() {
        sizeInByte = getSize();
    }
}
