package com.atlassian.stash.internal.scm.git.command.catfile;

import com.atlassian.bitbucket.scm.git.GitUtils;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

/**
 * Header in the output of a {@code git cat-file --batch} or {@code git cat-file --batch-check} command.
 */
public class BatchHeader {

    public static int MAX_SIZE_IN_BYTES = 100;

    private final String objectId;
    private final String type;
    private final long size;

    private BatchHeader(String objectId, String type, long size) {
        this.objectId = objectId;
        this.type = type;
        this.size = size;
    }

    public String getObjectId() {
        return objectId;
    }

    public String getType() {
        return type;
    }

    public long getSize() {
        return size;
    }

    public boolean isMissing() {
        return "missing".equals(type);
    }

    public static BatchHeader parse(byte[] bytes) {
        // Output for found objects looks like this:
        //   <sha1> SP <type> SP <size> LF
        // For missing objects:
        //   <object> SP missing LF

        ByteArrayInputStream header = new ByteArrayInputStream(bytes);
        Scanner scanner = new Scanner(header, StandardCharsets.UTF_8.name());

        String sha1 = getSha1(scanner);
        String type = getType(scanner);
        if ("missing".equals(type)) {
            return new BatchHeader(sha1, type, 0);
        }

        long size = getSize(scanner);
        return new BatchHeader(sha1, type, size);
    }

    private static String getSha1(Scanner headerScanner) {
        if (headerScanner.hasNext()) {
            String hdrSha1 = headerScanner.next();
            if (GitUtils.isHash(hdrSha1)) {
                return hdrSha1;
            } else {
                // Sha1 is not a SHA...
                throw new IllegalStateException("The SHA1 received was not exactly 40 characters in size, was: " + hdrSha1);
            }
        }
        throw new IllegalStateException("Expected a SHA1");
    }

    private static String getType(Scanner headerScanner) {
        if (headerScanner.hasNext()) {
            return headerScanner.next();
        }
        throw new IllegalStateException("Object type expected, but not found");
    }

    private static long getSize(Scanner headerScanner) {
        if (headerScanner.hasNext()) {
            String hdrSize = headerScanner.next();
            try {
                long size = Long.parseLong(hdrSize);
                if (size < 0) {
                    throw new IllegalStateException("The size cannot be negative");
                }
                return size;
            } catch (NumberFormatException e) {
                throw new IllegalStateException("The size field did not contain a valid number");
            }
        }
        throw new IllegalStateException("Content size expected but not found");
    }
}
