package ru.shine.promo.service;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import ru.shine.promo.config.AppProperties;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class UsedPromoStorageService {

    private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm", Locale.ROOT);

    private final AppProperties appProperties;
    private final ReentrantLock promoLock = new ReentrantLock(true);

    public UsedPromoStorageService(AppProperties appProperties) {
        this.appProperties = appProperties;
    }

    public <T> T executeLocked(LockedOperation<T> operation) {
        promoLock.lock();
        try {
            return operation.run();
        } finally {
            promoLock.unlock();
        }
    }

    public boolean isPromoUsed(String promoCode) {
        Path usedFile = Path.of(appProperties.getPromoUsedFile());
        if (!Files.exists(usedFile)) {
            return false;
        }

        try {
            List<String> rows = Files.readAllLines(usedFile, StandardCharsets.UTF_8);
            for (String row : rows) {
                String line = row.trim();
                if (line.isEmpty() || line.startsWith("#")) {
                    continue;
                }

                String[] parts = line.split("\\|");
                if (parts.length == 0) {
                    continue;
                }

                String usedCode = parts[0].trim().toLowerCase(Locale.ROOT);
                if (usedCode.equals(promoCode)) {
                    return true;
                }
            }
            return false;
        } catch (IOException e) {
            throw new PromoException(HttpStatus.INTERNAL_SERVER_ERROR, "Ошибка чтения файла использованных промокодов", e);
        }
    }

    public void appendUsedPromo(String promoCode, String wallet, String name, String signature) {
        Path usedFile = Path.of(appProperties.getPromoUsedFile());
        try {
            Path parent = usedFile.toAbsolutePath().getParent();
            if (parent != null) {
                Files.createDirectories(parent);
            }
            if (!Files.exists(usedFile)) {
                Files.createFile(usedFile);
            }

            String timestamp = LocalDateTime.now().format(DATE_TIME_FORMAT);
            String line = String.format(
                    Locale.ROOT,
                    "%s | %s | %s | %s | %s%n",
                    promoCode,
                    wallet,
                    name,
                    timestamp,
                    signature
            );

            Files.writeString(usedFile, line, StandardCharsets.UTF_8, StandardOpenOption.APPEND);
        } catch (IOException e) {
            throw new PromoException(HttpStatus.INTERNAL_SERVER_ERROR, "Ошибка записи файла использованных промокодов", e);
        }
    }

    @FunctionalInterface
    public interface LockedOperation<T> {
        T run();
    }
}
