package main

import (
	"encoding/base64"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

const mediaLockMagic = "CMVD"

func decryptMediaFile(encPath, keyB64, playName string) (string, func(), error) {
	key, err := base64.StdEncoding.DecodeString(keyB64)
	if err != nil || len(key) == 0 {
		return "", nil, fmt.Errorf("invalid media key")
	}
	in, err := os.Open(encPath)
	if err != nil {
		return "", nil, err
	}
	defer in.Close()

	head := make([]byte, len(mediaLockMagic))
	if _, err := io.ReadFull(in, head); err != nil || string(head) != mediaLockMagic {
		return "", nil, fmt.Errorf("not a locked media file")
	}

	dir, err := os.MkdirTemp("", "cm-fusion-play-*")
	if err != nil {
		return "", nil, err
	}
	outName := filepath.Base(playName)
	if outName == "" || outName == "." {
		outName = "movie.mkv"
	}
	outPath := filepath.Join(dir, outName)
	out, err := os.Create(outPath)
	if err != nil {
		os.RemoveAll(dir)
		return "", nil, err
	}

	buf := make([]byte, 256*1024)
	ki := 0
	for {
		n, readErr := in.Read(buf)
		if n > 0 {
			plain := make([]byte, n)
			for i := 0; i < n; i++ {
				plain[i] = buf[i] ^ key[ki%len(key)]
				ki++
			}
			if _, err := out.Write(plain); err != nil {
				out.Close()
				os.RemoveAll(dir)
				return "", nil, err
			}
		}
		if readErr == io.EOF {
			break
		}
		if readErr != nil {
			out.Close()
			os.RemoveAll(dir)
			return "", nil, readErr
		}
	}
	out.Close()
	return outPath, func() { _ = os.RemoveAll(dir) }, nil
}

func encryptedMediaBesideRunner(mediaEncFile, keyB64, playName string) (string, func(), error) {
	exe, err := os.Executable()
	if err != nil {
		return "", nil, err
	}
	name := strings.TrimSpace(mediaEncFile)
	if name == "" {
		return "", nil, fmt.Errorf("missing encrypted media name")
	}
	encPath := filepath.Join(filepath.Dir(exe), filepath.Base(name))
	if st, err := os.Stat(encPath); err != nil || st.IsDir() {
		return "", nil, fmt.Errorf("encrypted media not found")
	}
	return decryptMediaFile(encPath, keyB64, playName)
}
