package online.wesal.wesal.service;

import online.wesal.wesal.entity.Puzzle;
import online.wesal.wesal.entity.PuzzleAttempt;
import online.wesal.wesal.entity.User;
import online.wesal.wesal.repository.PuzzleAttemptRepository;
import online.wesal.wesal.repository.PuzzleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Random;

@Service
public class PuzzleService {
    
    @Autowired
    private PuzzleRepository puzzleRepository;
    
    @Autowired
    private PuzzleAttemptRepository puzzleAttemptRepository;
    
    @Autowired
    private UserService userService;
    
    private static final ZoneId RIYADH_TIMEZONE = ZoneId.of("Asia/Riyadh");
    private static final LocalTime CUTOFF_TIME = LocalTime.of(9, 0); // 9:00 AM
    
    private static final List<String> WORD_LIST = Arrays.asList(
        "APPLE", "BEACH", "CHAIN", "DANCE", "EAGLE", "FLAME", "GRAPE", "HOUSE", "IMAGE", "JUDGE",
        "KNIFE", "LIGHT", "MUSIC", "NIGHT", "OCEAN", "PEACE", "QUEEN", "RIVER", "STAGE", "TIGER",
        "UNITY", "VOICE", "WATER", "YOUTH", "ZEBRA", "ANGEL", "BREAD", "CHAIR", "DREAM", "EARTH",
        "FIELD", "GLASS", "HEART", "INDEX", "JUICE", "KITE", "LEMON", "MAGIC", "NOVEL", "OPERA",
        "PLANT", "QUEST", "RADIO", "SMILE", "TOWER", "ULTRA", "VILLA", "WORLD", "YOUTH", "ZEBRA",
        "ABOUT", "ABOVE", "ABUSE", "ACTOR", "ACUTE", "ADMIT", "ADOPT", "ADULT", "AFTER", "AGAIN",
        "AGENT", "AGREE", "AHEAD", "ALARM", "ALBUM", "ALERT", "ALIEN", "ALIGN", "ALIKE", "ALIVE",
        "ALLOW", "ALONE", "ALONG", "ALTER", "AMONG", "ANGER", "ANGLE", "ANGRY", "APART", "APPLE",
        "APPLY", "ARENA", "ARGUE", "ARISE", "ARRAY", "ASIDE", "ASSET", "AVOID", "AWAKE", "AWARD",
        "AWARE", "BADLY", "BAKER", "BASES", "BASIC", "BEACH", "BEGAN", "BEGIN", "BEING", "BELOW",
        "BENCH", "BILLY", "BIRTH", "BLACK", "BLAME", "BLANK", "BLIND", "BLOCK", "BLOOD", "BOARD",
        "BOOST", "BOOTH", "BOUND", "BRAIN", "BRAND", "BRASS", "BRAVE", "BREAD", "BREAK", "BREED",
        "BRIEF", "BRING", "BROAD", "BROKE", "BROWN", "BUILD", "BUILT", "BUYER", "CABLE", "CALIF",
        "CARRY", "CATCH", "CAUSE", "CHAIN", "CHAIR", "CHAOS", "CHARM", "CHART", "CHASE", "CHEAP",
        "CHECK", "CHEST", "CHIEF", "CHILD", "CHINA", "CHOSE", "CIVIL", "CLAIM", "CLASS", "CLEAN",
        "CLEAR", "CLICK", "CLIMB", "CLOCK", "CLOSE", "CLOUD", "COACH", "COAST", "COULD", "COUNT",
        "COURT", "COVER", "CRAFT", "CRASH", "CRAZY", "CREAM", "CRIME", "CROSS", "CROWD", "CROWN",
        "CRUDE", "CURVE", "CYCLE", "DAILY", "DAMAGE", "DANCE", "DATED", "DEALT", "DEATH", "DEBUG",
        "DELAY", "DEPTH", "DOING", "DOUBT", "DOZEN", "DRAFT", "DRAMA", "DRANK", "DRAWN", "DREAM",
        "DRESS", "DRILL", "DRINK", "DRIVE", "DROVE", "DYING", "EAGER", "EARLY", "EARTH", "EIGHT",
        "ELITE", "EMPTY", "ENEMY", "ENJOY", "ENTER", "ENTRY", "EQUAL", "ERROR", "EVENT", "EVERY",
        "EXACT", "EXIST", "EXTRA", "FAITH", "FALSE", "FAULT", "FIBER", "FIELD", "FIFTH", "FIFTY",
        "FIGHT", "FINAL", "FIRST", "FIXED", "FLASH", "FLEET", "FLOOR", "FLUID", "FOCUS", "FORCE",
        "FORTH", "FORTY", "FORUM", "FOUND", "FRAME", "FRANK", "FRAUD", "FRESH", "FRONT", "FRUIT",
        "FULLY", "FUNNY", "GIANT", "GIVEN", "GLASS", "GLOBE", "GOING", "GRACE", "GRADE", "GRAND",
        "GRANT", "GRASS", "GRAVE", "GREAT", "GREEN", "GROSS", "GROUP", "GROWN", "GUARD", "GUESS",
        "GUEST", "GUIDE", "HAPPY", "HARRY", "HEART", "HEAVY", "HENCE", "HENRY", "HORSE", "HOTEL",
        "HOUSE", "HUMAN", "IDEAL", "IMAGE", "INDEX", "INNER", "INPUT", "ISSUE", "JAPAN", "JIMMY",
        "JOINT", "JONES", "JUDGE", "KNOWN", "LABEL", "LARGE", "LASER", "LATER", "LAUGH", "LAYER",
        "LEARN", "LEASE", "LEAST", "LEAVE", "LEGAL", "LEVEL", "LEWIS", "LIGHT", "LIMIT", "LINKS",
        "LIVES", "LOCAL", "LOOSE", "LOWER", "LUCKY", "LUNCH", "LYING", "MAGIC", "MAJOR", "MAKER",
        "MARCH", "MARIA", "MATCH", "MAYBE", "MAYOR", "MEANT", "MEDIA", "METAL", "MIGHT", "MINOR",
        "MINUS", "MIXED", "MODEL", "MONEY", "MONTH", "MORAL", "MOTOR", "MOUNT", "MOUSE", "MOUTH",
        "MOVED", "MOVIE", "MUSIC", "NEEDS", "NEVER", "NEWLY", "NIGHT", "NOISE", "NORTH", "NOTED",
        "NOVEL", "NURSE", "OCCUR", "OCEAN", "OFFER", "OFTEN", "ORDER", "OTHER", "OUGHT", "PAINT",
        "PANEL", "PAPER", "PARTY", "PEACE", "PETER", "PHASE", "PHONE", "PHOTO", "PIANO", "PICKED",
        "PIECE", "PILOT", "PITCH", "PLACE", "PLAIN", "PLANE", "PLANT", "PLATE", "POINT", "POUND",
        "POWER", "PRESS", "PRICE", "PRIDE", "PRIME", "PRINT", "PRIOR", "PRIZE", "PROOF", "PROUD",
        "PROVE", "QUEEN", "QUICK", "QUIET", "QUITE", "RADIO", "RAISE", "RANGE", "RAPID", "RATIO",
        "REACH", "READY", "REALM", "REBEL", "REFER", "RELAX", "RELAY", "RIDER", "RIDGE", "RIGHT",
        "RIGID", "RIVAL", "RIVER", "ROBIN", "ROGER", "ROMAN", "ROUGH", "ROUND", "ROUTE", "ROYAL",
        "RURAL", "SCALE", "SCENE", "SCOPE", "SCORE", "SENSE", "SERVE", "SEVEN", "SHALL", "SHAPE",
        "SHARE", "SHARP", "SHEET", "SHELF", "SHELL", "SHIFT", "SHINE", "SHIRT", "SHOCK", "SHOOT",
        "SHORT", "SHOWN", "SIGHT", "SILLY", "SINCE", "SIXTH", "SIXTY", "SIZED", "SKILL", "SLEEP",
        "SLIDE", "SMALL", "SMART", "SMILE", "SMITH", "SMOKE", "SNAKE", "SNOW", "SOBER", "SORRY",
        "SOUND", "SOUTH", "SPACE", "SPARE", "SPEAK", "SPEED", "SPEND", "SPENT", "SPLIT", "SPOKE",
        "SPORT", "STAFF", "STAGE", "STAKE", "STAND", "START", "STATE", "STEAM", "STEEL", "STEEP",
        "STEER", "STERN", "STICK", "STILL", "STOCK", "STONE", "STOOD", "STORE", "STORM", "STORY",
        "STRIP", "STUCK", "STUDY", "STUFF", "STYLE", "SUGAR", "SUITE", "SUPER", "SWEET", "TABLE",
        "TAKEN", "TASTE", "TAXES", "TEACH", "TEAM", "TEETH", "TERRY", "THANK", "THEFT", "THEIR",
        "THEME", "THERE", "THESE", "THICK", "THING", "THINK", "THIRD", "THOSE", "THREE", "THREW",
        "THROW", "THUMB", "TIGER", "TIGHT", "TIMES", "TIRED", "TITLE", "TODAY", "TOPIC", "TOTAL",
        "TOUCH", "TOUGH", "TOWER", "TRACK", "TRADE", "TRAIN", "TREAT", "TREND", "TRIAL", "TRIBE",
        "TRICK", "TRIED", "TRIES", "TRIP", "TRUCK", "TRULY", "TRUNK", "TRUST", "TRUTH", "TWICE",
        "UNDER", "UNDUE", "UNION", "UNITY", "UNTIL", "UPPER", "UPSET", "URBAN", "USAGE", "USUAL",
        "VALUE", "VIDEO", "VIRUS", "VISIT", "VITAL", "VOCAL", "VOICE", "WASTE", "WATCH", "WATER",
        "WHEEL", "WHERE", "WHICH", "WHILE", "WHITE", "WHOLE", "WHOSE", "WOMAN", "WOMEN", "WORLD",
        "WORRY", "WORSE", "WORST", "WORTH", "WOULD", "WRITE", "WRONG", "WROTE", "YOUNG", "YOUTH"
    );
    
    public Puzzle getTodaysPuzzle() {
        LocalDate today = getRiyadhToday();
        Optional<Puzzle> existingPuzzle = puzzleRepository.findByDate(today);
        
        if (existingPuzzle.isPresent()) {
            return existingPuzzle.get();
        }
        
        String word = generateWordForDate(today);
        Puzzle puzzle = new Puzzle(today, word);
        return puzzleRepository.save(puzzle);
    }
    
    private String generateWordForDate(LocalDate date) {
        Random random = new Random(date.toEpochDay());
        return WORD_LIST.get(random.nextInt(WORD_LIST.size()));
    }
    
    private LocalDate getRiyadhToday() {
        return ZonedDateTime.now(RIYADH_TIMEZONE).toLocalDate();
    }
    
    private LocalDateTime getRiyadhNow() {
        return ZonedDateTime.now(RIYADH_TIMEZONE).toLocalDateTime();
    }
    
    private LocalDate getLeaderboardDate() {
        LocalDateTime riyadhNow = getRiyadhNow();
        LocalDate today = riyadhNow.toLocalDate();
        
        // If it's before 9 AM, show yesterday's leaderboard
        if (riyadhNow.toLocalTime().isBefore(CUTOFF_TIME)) {
            return today.minusDays(1);
        }
        // From 9 AM onwards, show today's leaderboard
        return today;
    }
    
    public boolean hasUserSolvedToday() {
        User currentUser = userService.getCurrentUser();
        Puzzle todaysPuzzle = getTodaysPuzzle();
        
        Optional<PuzzleAttempt> attempt = puzzleAttemptRepository.findByUserAndPuzzle(currentUser, todaysPuzzle);
        return attempt.isPresent();
    }
    
    public Optional<PuzzleAttempt> getUserTodaysAttempt() {
        User currentUser = userService.getCurrentUser();
        Puzzle todaysPuzzle = getTodaysPuzzle();
        
        return puzzleAttemptRepository.findByUserAndPuzzle(currentUser, todaysPuzzle);
    }
    
    public PuzzleAttempt submitAttempt(int attempts, boolean solved) {
        User currentUser = userService.getCurrentUser();
        Puzzle todaysPuzzle = getTodaysPuzzle();
        
        Optional<PuzzleAttempt> existingAttempt = puzzleAttemptRepository.findByUserAndPuzzle(currentUser, todaysPuzzle);
        if (existingAttempt.isPresent()) {
            throw new RuntimeException("You've already attempted the daily challenge");
        }
        
        PuzzleAttempt attempt = new PuzzleAttempt(currentUser, todaysPuzzle, attempts, solved);
        return puzzleAttemptRepository.save(attempt);
    }
    
    public List<PuzzleAttempt> getTodaysLeaderboard() {
        LocalDate leaderboardDate = getLeaderboardDate();
        Optional<Puzzle> puzzleOpt = puzzleRepository.findByDate(leaderboardDate);
        
        if (puzzleOpt.isEmpty()) {
            // If no puzzle exists for the leaderboard date, return empty list
            return Arrays.asList();
        }
        
        return puzzleAttemptRepository.findByPuzzleOrderBySubmittedAtAsc(puzzleOpt.get());
    }
    
}