"""Run: python -m unittest -v test_analysis.py (from this directory)."""
import csv
import io
from pathlib import Path
import tempfile
import unittest
from analyze_festival import read_validated, summarize, chart, write_results

HERE = Path(__file__).parent

class AnalysisTests(unittest.TestCase):
    def test_known_totals(self):
        s = summarize(read_validated(HERE/'festival.csv'))
        self.assertEqual(s['row_count'], 8)
        self.assertEqual(s['total_entries'], 1000)
        self.assertEqual(s['total_cups'], 270)
        self.assertEqual(s['cups_per_100_entries'], 27)
        self.assertEqual([d['cups'] for d in s['daily']], [150, 120])
        self.assertEqual([d['cups_per_100_entries'] for d in s['daily']], [25, 30])
        self.assertEqual(s['unweighted_daily_rate_mean'], 27.5)

    def read_text(self, text):
        with tempfile.TemporaryDirectory(dir=HERE) as d:
            path = Path(d)/'test.csv'
            path.write_text(text, encoding='utf-8')
            return read_validated(path)

    def test_compact_date_is_not_accepted_as_iso_display_date(self):
        with self.assertRaisesRegex(ValueError, 'ISO date'):
            self.read_text((HERE/'festival.csv').read_text().replace('2026-11-07','20261107'))

    def test_extended_chart_keeps_gap_between_bars(self):
        import re
        summary={'daily':[{'day':f'2026-11-{day:02d}','cups':30} for day in range(1,11)]}
        svg=chart(summary,'cups',180,30,'販売杯数（杯）')
        self.assertEqual(len(re.findall('width="44.8"',svg)),10)

    def test_duplicate_rejected(self):
        text = (HERE/'festival.csv').read_text()
        with self.assertRaisesRegex(ValueError, 'duplicate'):
            self.read_text(text + text.splitlines()[1]+'\n')

    def test_missing_not_zero(self):
        text = (HERE/'festival.csv').read_text().replace(',180,54', ',180,')
        with self.assertRaisesRegex(ValueError, 'blank is not zero'):
            self.read_text(text)

    def test_non_integer_rejected(self):
        text = (HERE/'festival.csv').read_text().replace(',120,24', ',120,24.5', 1)
        with self.assertRaisesRegex(ValueError, 'non-negative integer'):
            self.read_text(text)

    def test_zero_denominator_rejected(self):
        text = 'day,slot,entries,cups\n2026-11-07,10:00-11:00,0,0\n'
        with self.assertRaisesRegex(ValueError, 'undefined'):
            summarize(self.read_text(text))

    def test_multiple_cups_per_entry_allowed(self):
        text = 'day,slot,entries,cups\n2026-11-07,10:00-11:00,2,3\n'
        self.assertEqual(summarize(self.read_text(text))['cups_per_100_entries'], 150)

    def test_chart_exact_bar_heights(self):
        s = summarize(read_validated(HERE/'festival.csv'))
        svg = chart(s,'cups_per_100_entries',40,10,'杯 / 入場100回')
        # plot height 290. 25/40*290=181.25 and 30/40*290=217.5.
        self.assertIn('height="181.25"', svg)
        self.assertIn('height="217.50"', svg)

    def test_range_failure_preserves_previous_bundle(self):
        with tempfile.TemporaryDirectory() as folder:
            root = Path(folder)
            output = root/'results'
            write_results(HERE/'festival.csv', output)
            before = {p.name: p.read_bytes() for p in output.iterdir()}
            invalid = root/'changed.csv'
            invalid.write_text((HERE/'festival.csv').read_text().replace(',120,24', ',120,124', 1))
            with self.assertRaisesRegex(ValueError, 'range exceeded'):
                write_results(invalid, output)
            self.assertEqual(before, {p.name: p.read_bytes() for p in output.iterdir()})

    def test_range_failure_creates_no_output(self):
        with tempfile.TemporaryDirectory() as folder:
            root = Path(folder)
            invalid = root/'changed.csv'
            invalid.write_text((HERE/'festival.csv').read_text().replace(',120,24', ',120,124', 1))
            with self.assertRaisesRegex(ValueError, 'range exceeded'):
                write_results(invalid, root/'new'/'results')
            self.assertFalse((root/'new').exists())

    def test_successful_bundle_matches_rendered_summary(self):
        import json
        with tempfile.TemporaryDirectory() as folder:
            output = Path(folder)/'results'
            summary = write_results(HERE/'festival.csv', output)
            self.assertEqual(json.loads((output/'summary.json').read_text()), summary)
            self.assertEqual(set(p.name for p in output.iterdir()), {'summary.json','daily_summary.csv','cups-by-day.svg','rate-by-day.svg'})
            with (output/'daily_summary.csv').open(newline='') as stream:
                rows = list(csv.DictReader(stream))
            self.assertEqual([int(row['cups']) for row in rows], [150, 120])

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