package com.javarush.task.task39.task3913;

import com.javarush.task.task39.task3913.query.IPQuery;

import java.io.*;
import java.nio.file.Path;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class LogParser implements IPQuery {

    private Path fileLogs;
    List<String> logs;
    List<Log> logList;

    public LogParser(Path logDir) {
        fileLogs = logDir;
        logs = helper(logDir.toFile().listFiles());
        logList = parseStringsToLogs(logs);
    }

    @Override
    public int getNumberOfUniqueIPs(Date after, Date before) {
        return getUniqueIPs(after, before).size();
    }

    @Override
    public Set<String> getUniqueIPs(Date after, Date before) {
        Set<String> ipsUnique = new HashSet<>();
        try {
            List<Log> tempList = sortLogToDate(logList, after, before);
            for(Log log: tempList){
                if (log == null) break;
                ipsUnique.add(log.IP);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ipsUnique;
    }

    @Override
    public Set<String> getIPsForUser(String user, Date after, Date before) {
        Set<String> resultIPs = new HashSet<>();
        List<Log> inter = sortLogToDate(logList, after, before);
        for(Log log: inter){
            if(log.name.equals(user)) resultIPs.add(log.IP);
        }
        return resultIPs;
    }

    @Override
    public Set<String> getIPsForEvent(Event event, Date after, Date before) {
        Set<String> resultIPs = new HashSet<>();
        List<Log> inter = sortLogToDate(logList, after, before);
        for(Log log: inter){
            if(log.event == event) resultIPs.add(log.IP);
        }
        return resultIPs;
    }

    @Override
    public Set<String> getIPsForStatus(Status status, Date after, Date before) {
        Set<String> resultIPs = new HashSet<>();
        List<Log> inter = sortLogToDate(logList, after, before);
        for(Log log: inter){
            if(status == log.status) resultIPs.add(log.IP);
        }
        return resultIPs;
    }

    //Вытаскивает из файлов логов строки и формирует массив с логами.
    private List<String> helper(File[] files) {
        List<String> outputList = new ArrayList<>();
        try {
            BufferedReader reader;
            for(File f: files){
                FileReader fileReader = new FileReader(f);
                reader = new BufferedReader(fileReader);
                String s ="";
                while (true){
                    s = reader.readLine();
                    if(s == null) break;
                    outputList.add(s);
                }
                fileReader.close();
                reader.close();
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        return outputList;
    }
    //Возвращаем заданый промежуток дат.
    private List<Log> sortLogToDate(List<Log> list, Date after, Date before){
        List<Log> result = new ArrayList<>();
        List<Log> inter = new ArrayList<>(list);
        Date oneDate = null;
        Date twoDate = null;
        //Сортировка логов по датам
        for(int i1 = 0; i1 < inter.size(); i1++){
            for(int i2 = 0; i2 < inter.size(); i2++){
                oneDate = inter.get(i1).date;
                twoDate = inter.get(i2).date;
                if(oneDate.getTime() < twoDate.getTime()){
                    Log log = inter.get(i1);
                    inter.set(i1, inter.get(i2));
                    inter.set(i2, log);
                }
            }
        }
        //Собираем нужный промежуток дат
        for(Log log : inter){
            Date temp = log.date;
            if(after == null && before == null){
                result.add(log);
            }else if(after == null){
                if(temp.getTime() <= before.getTime()){
                    result.add(log);
                }
            }else if(before == null){
                if(temp.getTime() >= after.getTime()){
                    result.add(log);
                }
            }else{
                if((temp.getTime() <= before.getTime()) && (temp.getTime() >= after.getTime())){
                    result.add(log);
                }
            }
        }
        return result;
    }
    //парсер дат
    private Date parseDate(String dateString) {
        Date date = null;
        try {
            String format = "d.M.y H:m:s";
            DateFormat dateFormat = new SimpleDateFormat(format);
            date = dateFormat.parse(dateString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    //Создаём из строк логов список экземпляров класса Log
    private List<Log> parseStringsToLogs(List<String> logsList){
        String IP = "";
        String name = "";
        Date date = null;
        Event event = null;
        String numberTack = "";
        Status status = null;

        List<Log> result = new ArrayList<>();
        String interEvent = "";
        String[] partsOfLog;

        for(String s: logsList){
            partsOfLog = s.split("\\t");
            IP = partsOfLog[0];
            name = partsOfLog[1];
            date = parseDate(partsOfLog[2]);
            interEvent = partsOfLog[3];

            if(interEvent.split("\\s").length == 2){
                String nameEvent = interEvent.split("\\s")[0];
                event = Event.valueOf(nameEvent);
                numberTack = interEvent.split("\\s")[1];
            }else {
                String nameEvent = interEvent.split("\\s")[0];
                event = Event.valueOf(nameEvent);
            }

            String statusTemp = partsOfLog[4];
            status = Status.valueOf(statusTemp);

            result.add(new Log(IP, name, date, event, numberTack, status));
        }
        return result;
    }


    private static class Log {
        String IP = "";
        String name = "";
        Date date = null;
        Event event = null;
        String numberTack = "";
        Status status = null;

        public Log(String IP, String name, Date date, Event event, String numberTack, Status status) {
            this.IP = IP;
            this.name = name;
            this.date = date;
            this.event = event;
            this.numberTack = numberTack;
            this.status = status;
        }
    }

}