import os
import sqlite3
import threading
import time
import unittest
import tempfile
from http.server import HTTPServer

import requests

from random_com_app.backend_python.server import (
    GiveawayRequestHandler,
    init_db,
    record_audit,
    now,
)


class GiveawayServerTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # Create temporary DB
        cls.temp_db_fd, cls.temp_db_path = tempfile.mkstemp(suffix='.db')
        os.close(cls.temp_db_fd)
        os.environ['DB_PATH'] = cls.temp_db_path
        # Initialize DB
        init_db()
        # Start server in thread
        cls.port = 8001
        cls.server = HTTPServer(('127.0.0.1', cls.port), GiveawayRequestHandler)
        cls.thread = threading.Thread(target=cls.server.serve_forever)
        cls.thread.daemon = True
        cls.thread.start()
        # Wait briefly for server to start
        time.sleep(0.3)

    @classmethod
    def tearDownClass(cls):
        cls.server.shutdown()
        cls.thread.join()
        if os.path.exists(cls.temp_db_path):
            os.unlink(cls.temp_db_path)

    def base_url(self, path: str) -> str:
        return f'http://127.0.0.1:{self.port}{path}'

    def test_create_and_get_giveaway(self):
        # Create giveaway
        resp = requests.post(
            self.base_url('/api/giveaways'),
            json={'title': 'Python Test', 'prize': 'Coffee Mug', 'number_of_winners': 2},
        )
        self.assertEqual(resp.status_code, 201)
        gid = resp.json()['id']
        # List giveaways
        list_resp = requests.get(self.base_url('/api/giveaways'))
        self.assertEqual(list_resp.status_code, 200)
        self.assertTrue(any(g['id'] == gid for g in list_resp.json()))
        # Get details
        detail_resp = requests.get(self.base_url(f'/api/giveaways/{gid}'))
        self.assertEqual(detail_resp.status_code, 200)
        data = detail_resp.json()
        self.assertEqual(data['title'], 'Python Test')
        self.assertEqual(data['prize'], 'Coffee Mug')
        self.assertEqual(data['entrantCount'], 0)
        self.assertEqual(data['winnerCount'], 0)

    def test_enter_and_draw(self):
        # Create giveaway with 1 winner
        resp = requests.post(
            self.base_url('/api/giveaways'),
            json={'title': 'Draw Test', 'prize': 'Book', 'number_of_winners': 1},
        )
        gid = resp.json()['id']
        # Enter two participants
        e1 = requests.post(
            self.base_url(f'/api/giveaways/{gid}/enter'),
            json={'email': 'alice@example.com', 'username': 'Alice'},
        )
        self.assertEqual(e1.status_code, 201)
        e2 = requests.post(
            self.base_url(f'/api/giveaways/{gid}/enter'),
            json={'email': 'bob@example.com', 'username': 'Bob'},
        )
        self.assertEqual(e2.status_code, 201)
        # Duplicate should fail
        dup = requests.post(
            self.base_url(f'/api/giveaways/{gid}/enter'),
            json={'email': 'alice@example.com'},
        )
        self.assertEqual(dup.status_code, 409)
        # Draw winners
        draw = requests.post(self.base_url(f'/api/giveaways/{gid}/draw'))
        self.assertEqual(draw.status_code, 200)
        result = draw.json()
        self.assertEqual(len(result['winners']), 1)
        # Re-draw should be conflict
        draw_again = requests.post(self.base_url(f'/api/giveaways/{gid}/draw'))
        self.assertEqual(draw_again.status_code, 409)


if __name__ == '__main__':
    unittest.main()