package com.atlassian.bitbucket.content;

import com.atlassian.bitbucket.commit.SimpleMinimalCommit;
import com.atlassian.bitbucket.user.Person;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;

import static com.google.common.base.Preconditions.checkArgument;

public class SimpleBlame implements Blame {
    
    private final Person author;
    private final Date authorTimestamp;
    private final String commitId;
    private final String displayCommitId;
    private final String fileName;
    private final int lineNumber;
    private final int spannedLines;

    private SimpleBlame(int lineNumber, int spannedLines, String commitId, String displayCommitId,
                        String fileName, Person author, Date authorTimestamp) {
        this.author = author;
        this.authorTimestamp = authorTimestamp;
        this.commitId = commitId;
        this.displayCommitId = displayCommitId;
        this.fileName = fileName;
        this.lineNumber = lineNumber;
        this.spannedLines = spannedLines;
    }

    @Override
    public Person getAuthor() {
        return author;
    }

    @Override
    public Date getAuthorTimestamp() {
        return authorTimestamp;
    }

    @Override
    public String getCommitId() {
        return commitId;
    }

    @Override
    public String getCommitDisplayId() {
        return displayCommitId;
    }

    @Override
    public String getFileName() {
        return fileName;
    }

    @Override
    public int getLineNumber() {
        return lineNumber;
    }

    @Override
    public int getSpannedLines() {
        return spannedLines;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder().append(lineNumber);
        if (spannedLines > 1) {
            builder.append("-").append(lineNumber + spannedLines - 1);
        }
        builder.append(":").append(commitId)
                .append(" ").append(author).append(" ").append(authorTimestamp)
                .append(" (").append(fileName).append(")");

        return builder.toString();
    }

    public static final class Builder {

        private Person author;
        private Date authorTimestamp;
        private String commitId;
        private String displayCommitId;
        private String fileName;
        private int lineNumber;
        private int spannedLines;

        public Builder() {
            
        }
        
        public Builder(Blame blame) {
            author = blame.getAuthor();
            authorTimestamp = blame.getAuthorTimestamp();
            commitId = blame.getCommitId();
            displayCommitId = blame.getCommitDisplayId();
            fileName = blame.getFileName();
            lineNumber = blame.getLineNumber();
            spannedLines = blame.getSpannedLines();
        }
        
        public Builder author(Person value) {
            author = value;
            
            return this;
        }
        
        public Builder authorTimestamp(Date value) {
            authorTimestamp = value;
            
            return this;
        }

        public SimpleBlame build() {
            checkArgument(lineNumber > 0, "Line numbers begin at 1 and are required");
            //noinspection ConstantConditions
            checkArgument(author.getName() != null && authorTimestamp != null,
                    "Author information (name and timestamp) is required");
            checkArgument(StringUtils.isNotBlank(commitId), "A commit hash is required");
            checkArgument(StringUtils.isNotBlank(fileName), "A filename is required");

            if (displayCommitId == null) {
                displayCommitId = commitId.substring(0, SimpleMinimalCommit.DEFAULT_DISPLAY_ID_LENGTH);
            }
            if (spannedLines < 1) {
                spannedLines = 1;
            }

            return new SimpleBlame(lineNumber, spannedLines, commitId, displayCommitId,
                    fileName, author, authorTimestamp);
        }
        
        public Builder commitId(String value) {
            commitId = value;

            return this;
        }
        
        public Builder fileName(String value) {
            fileName = value;

            return this;
        }

        public Builder lineNumber(int value) {
            lineNumber = value;

            return this;
        }

        public Builder spannedLines(int value) {
            spannedLines = value;

            return this;
        }
    }
}
