package epubzip

import (
	"archive/zip"
	"image"
	"os"
	"sync"
)

type StorageImageWriter struct {
	fh     *os.File
	fz     *zip.Writer
	format string
	mut    *sync.Mutex
}

func NewStorageImageWriter(filename string, format string) (StorageImageWriter, error) {
	fh, err := os.Create(filename)
	if err != nil {
		return StorageImageWriter{}, err
	}
	fz := zip.NewWriter(fh)
	return StorageImageWriter{fh, fz, format, &sync.Mutex{}}, nil
}

func (e StorageImageWriter) Close() error {
	if err := e.fz.Close(); err != nil {
		_ = e.fh.Close()
		return err
	}
	return e.fh.Close()
}

func (e StorageImageWriter) Add(filename string, img image.Image, quality int) error {
	zipImage, err := CompressImage(filename, e.format, img, quality)
	if err != nil {
		return err
	}

	e.mut.Lock()
	defer e.mut.Unlock()
	fh, err := e.fz.CreateRaw(zipImage.Header)
	if err != nil {
		return err
	}
	_, err = fh.Write(zipImage.Data)
	if err != nil {
		return err
	}

	return nil
}

type StorageImageReader struct {
	filename string
	fh       *os.File
	fz       *zip.Reader

	files map[string]*zip.File
}

func NewStorageImageReader(filename string) (StorageImageReader, error) {
	fh, err := os.Open(filename)
	if err != nil {
		return StorageImageReader{}, err
	}
	s, err := fh.Stat()
	if err != nil {
		return StorageImageReader{}, err
	}
	fz, err := zip.NewReader(fh, s.Size())
	if err != nil {
		return StorageImageReader{}, err
	}
	files := map[string]*zip.File{}
	for _, z := range fz.File {
		files[z.Name] = z
	}
	return StorageImageReader{filename, fh, fz, files}, nil
}

func (e StorageImageReader) Get(filename string) *zip.File {
	return e.files[filename]
}

func (e StorageImageReader) Size(filename string) uint64 {
	if img, ok := e.files[filename]; ok {
		return img.CompressedSize64 + 30 + uint64(len(img.Name))
	}
	return 0
}

func (e StorageImageReader) Close() error {
	return e.fh.Close()
}

func (e StorageImageReader) Remove() error {
	return os.Remove(e.filename)
}