package commands

import (
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"os"

	"git.cheetah.cat/cheetah/moto-flash-data/flashpart"
	"github.com/rs/zerolog/log"
)

type MparPackCommand struct {
	SourceFileName     string `long:"src" short:"i" required:"true" description:"input-filename"`
	OriginalFullHeader string `long:"full-header" required:"true" description:"original full header hex"`

	DestFileName string `long:"dest" short:"o" required:"true" description:"output-filename"`
}

func (command *MparPackCommand) Execute(args []string) error {
	inputFile, err := os.Open(command.SourceFileName)
	if err != nil {
		return err
	}
	defer inputFile.Close()
	outputFile, err := os.Create(command.DestFileName)
	if err != nil {
		return err
	}
	defer outputFile.Close()

	inputFileStat, err := inputFile.Stat()
	if err != nil {
		return err
	}

	log.Info().Int64("fileSize", inputFileStat.Size()).Msg("Reading raw file...")
	rawData := make([]byte, inputFileStat.Size())
	_, err = io.ReadFull(inputFile, rawData)
	if err != nil {
		return err
	}

	originalHeader, err := hex.DecodeString(command.OriginalFullHeader)
	if len(originalHeader) != 32 {
		return errors.New("header invalid")
	}

	fpHeader := flashpart.ParseFlashPartHeader(originalHeader)
	log.Info().Msg(
		fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s",
			fpHeader.MediaID,
			fpHeader.TotalSize,
			fpHeader.TotalSize,
			fpHeader.VersionText,
		),
	)
	log.Info().Msg(
		fmt.Sprintf("Original-Full-Header-Hex: %s", hex.EncodeToString(fpHeader.GetBytes())),
	)
	fpHeader.AdjustRawSize(uint32(len(rawData)))

	log.Info().Msg(
		fmt.Sprintf("New-Full-Header-Hex:      %s", hex.EncodeToString(fpHeader.GetBytes())),
	)

	fpHeaderNew := flashpart.ParseFlashPartHeader(fpHeader.GetBytes())
	log.Info().Msg(
		fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s",
			fpHeaderNew.MediaID,
			fpHeaderNew.TotalSize,
			fpHeaderNew.TotalSize,
			fpHeaderNew.VersionText,
		),
	)

	_, err = outputFile.Write(fpHeaderNew.GetBytes())
	if err != nil {
		return err
	}
	_, err = outputFile.Write(rawData)
	if err != nil {
		return err
	}

	return nil
}