#pragma once

#include <string>
#include <vector>

class GitManager;
class AvatarCache;
struct RepositoryView;
struct ImFont;

class DiffViewer {
public:
    void open(RepositoryView& repository, GitManager& manager, const std::string& path,
        bool staged, std::string& notice);
    void openCommit(RepositoryView& repository, GitManager& manager, const std::string& path,
        const std::string& commit_id, std::string& notice);
    void close();
    bool isOpen() const { return !path_.empty(); }
    void draw(RepositoryView& repository, GitManager& manager, AvatarCache* avatars,
        float scale, ImFont* code_font, std::string& notice);

private:
    enum class Mode { diff, file, blame, history };
    enum class LineKind { context, added, removed };
    struct Line {
        int old_number = 0;
        int new_number = 0;
        LineKind kind = LineKind::context;
        std::string text;
        std::string raw;
    };
    struct Hunk {
        std::string header;
        std::vector<Line> lines;
        std::string patch;
    };
    struct BlameLine {
        std::string hash;
        std::string author;
        std::string email;
        std::string date;
        std::string summary;
        std::string text;
        int line_number = 0;
        bool show_attribution = false;
    };
    struct HistoryEntry {
        std::string hash;
        std::string date;
        std::string author;
        std::string summary;
    };

    std::string path_;
    std::string commit_id_;
    bool staged_ = false;
    Mode mode_ = Mode::diff;
    std::string file_header_;
    std::vector<Hunk> hunks_;
    std::vector<std::string> file_lines_;
    std::vector<BlameLine> blame_lines_;
    std::vector<HistoryEntry> history_entries_;
    bool line_wrap_ = false;
    bool scroll_to_top_ = false;

    void reload(RepositoryView& repository, GitManager& manager, std::string& notice);
    void loadSupplement(RepositoryView& repository, GitManager& manager, Mode mode, std::string& notice);
    void parseDiff(const std::string& text);
    void parseBlame(const std::string& text);
    void parseHistory(const std::string& text);
};
