"""Generate formatted text reports for differ results."""

import datetime
import os


def generate_differ_report(result, profile_config, baseline_id, output_path):
	"""
	Generate a well-formatted text report for differ results.
	
	Args:
		result: dict with differ results (from _current_results)
		profile_config: dict with profile settings (paths, languages, exclude_patterns)
		baseline_id: str, baseline identifier
		output_path: str, path where to save the report
	"""
	lines = []
	
	# Header
	lines.append("=" * 80)
	lines.append("PyUcc - Code Difference Report".center(80))
	lines.append("=" * 80)
	lines.append("")
	
	# Timestamp
	timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
	lines.append(f"Generated: {timestamp}")
	lines.append(f"Baseline ID: {baseline_id}")
	lines.append("")
	
	# Profile Configuration
	lines.append("-" * 80)
	lines.append("Profile Configuration")
	lines.append("-" * 80)
	lines.append(f"Profile Name: {profile_config.get('name', 'N/A')}")
	lines.append(f"Project Root: {profile_config.get('root', 'N/A')}")
	lines.append("")
	
	paths = profile_config.get('paths', [])
	if paths:
		lines.append(f"Included Paths ({len(paths)}):")
		for p in paths:
			lines.append(f"  - {p}")
	else:
		lines.append("Included Paths: All")
	lines.append("")
	
	languages = profile_config.get('languages', [])
	if languages:
		lines.append(f"Languages ({len(languages)}):")
		lang_str = ", ".join(languages)
		# Wrap at 70 chars
		if len(lang_str) > 70:
			lines.append(f"  {lang_str[:70]}")
			lines.append(f"  {lang_str[70:]}")
		else:
			lines.append(f"  {lang_str}")
	else:
		lines.append("Languages: All")
	lines.append("")
	
	exclude_patterns = profile_config.get('exclude_patterns', [])
	if exclude_patterns:
		lines.append(f"Exclude Patterns ({len(exclude_patterns)}):")
		for pat in exclude_patterns:
			lines.append(f"  - {pat}")
	else:
		lines.append("Exclude Patterns: None")
	lines.append("")
	
	# Summary Statistics
	lines.append("-" * 80)
	lines.append("Summary Statistics")
	lines.append("-" * 80)
	
	total = result.get('total', {})
	lines.append(f"Files Added:      {total.get('added', 0):>8}")
	lines.append(f"Files Deleted:    {total.get('deleted', 0):>8}")
	lines.append(f"Files Modified:   {total.get('modified', 0):>8}")
	lines.append(f"Files Unmodified: {total.get('unmodified', 0):>8}")
	lines.append(f"{'─' * 30}")
	total_files = sum([total.get('added', 0), total.get('deleted', 0), 
	                   total.get('modified', 0), total.get('unmodified', 0)])
	lines.append(f"Total Files:      {total_files:>8}")
	lines.append("")
	
	# Baseline vs Current metrics
	summary = result.get('summary', {})
	if summary:
		baseline_counts = summary.get('baseline', {}).get('countings', {})
		current_counts = summary.get('current', {}).get('countings', {})
		baseline_metrics = summary.get('baseline', {}).get('metrics', {})
		current_metrics = summary.get('current', {}).get('metrics', {})
		
		lines.append("-" * 80)
		lines.append("Code Metrics Comparison")
		lines.append("-" * 80)
		lines.append(f"{'Metric':<30} {'Baseline':>15} {'Current':>15} {'Delta':>15}")
		lines.append("─" * 80)
		
		# Countings
		def _delta_str(baseline_val, current_val):
			delta = current_val - baseline_val
			sign = "+" if delta >= 0 else ""
			return f"{sign}{delta}"
		
		bc_code = baseline_counts.get('code_lines', 0)
		cc_code = current_counts.get('code_lines', 0)
		lines.append(f"{'Code Lines':<30} {bc_code:>15,} {cc_code:>15,} {_delta_str(bc_code, cc_code):>15}")
		
		bc_comment = baseline_counts.get('comment_lines', 0)
		cc_comment = current_counts.get('comment_lines', 0)
		lines.append(f"{'Comment Lines':<30} {bc_comment:>15,} {cc_comment:>15,} {_delta_str(bc_comment, cc_comment):>15}")
		
		bc_blank = baseline_counts.get('blank_lines', 0)
		cc_blank = current_counts.get('blank_lines', 0)
		lines.append(f"{'Blank Lines':<30} {bc_blank:>15,} {cc_blank:>15,} {_delta_str(bc_blank, cc_blank):>15}")
		
		bc_physical = baseline_counts.get('physical_lines', 0)
		cc_physical = current_counts.get('physical_lines', 0)
		lines.append(f"{'Physical Lines':<30} {bc_physical:>15,} {cc_physical:>15,} {_delta_str(bc_physical, cc_physical):>15}")
		
		lines.append("")
		
		# Metrics
		bm_func = baseline_metrics.get('total_func_count', 0)
		cm_func = current_metrics.get('total_func_count', 0)
		lines.append(f"{'Function Count':<30} {bm_func:>15,} {cm_func:>15,} {_delta_str(bm_func, cm_func):>15}")
		
		bm_avgcc = baseline_metrics.get('avg_avg_cc', 0.0)
		cm_avgcc = current_metrics.get('avg_avg_cc', 0.0)
		lines.append(f"{'Avg Cyclomatic Complexity':<30} {bm_avgcc:>15.2f} {cm_avgcc:>15.2f} {_delta_str(bm_avgcc, cm_avgcc):>15}")
		
		bm_mi = baseline_metrics.get('avg_mi', 0.0)
		cm_mi = current_metrics.get('avg_mi', 0.0)
		lines.append(f"{'Maintainability Index':<30} {bm_mi:>15.2f} {cm_mi:>15.2f} {_delta_str(bm_mi, cm_mi):>15}")
		
		lines.append("")
	
	# Detailed File List
	lines.append("-" * 80)
	lines.append("Detailed File Changes")
	lines.append("-" * 80)
	lines.append("")
	
	pairs = result.get('pairs', [])
	
	# Group by status
	added_files = []
	deleted_files = []
	modified_files = []
	unmodified_files = []
	
	for pair in pairs:
		counts = pair.get('counts', {})
		if counts.get('added', 0) > 0:
			added_files.append(pair)
		elif counts.get('deleted', 0) > 0:
			deleted_files.append(pair)
		elif counts.get('modified', 0) > 0:
			modified_files.append(pair)
		else:
			unmodified_files.append(pair)
	
	# Added files
	if added_files:
		lines.append(f"Added Files ({len(added_files)}):")
		lines.append("─" * 80)
		for pair in added_files:
			current_name = pair.get('fileB', '')
			cd = pair.get('countings_delta')
			md = pair.get('metrics_delta')
			cur_m = pair.get('current_metrics')
			
			lines.append(f"  + {current_name}")
			if cd:
				lines.append(f"      Code: {cd.get('code_lines', 0):>6}  Comment: {cd.get('comment_lines', 0):>6}  Blank: {cd.get('blank_lines', 0):>6}")
			if cur_m:
				lines.append(f"      Functions: {cur_m.get('func_count', 0):>4}  Avg CC: {cur_m.get('avg_cc', 0.0):>6.2f}  MI: {cur_m.get('mi', 0.0):>6.2f}")
		lines.append("")
	
	# Deleted files
	if deleted_files:
		lines.append(f"Deleted Files ({len(deleted_files)}):")
		lines.append("─" * 80)
		for pair in deleted_files:
			baseline_name = pair.get('fileA', '')
			lines.append(f"  - {baseline_name}")
		lines.append("")
	
	# Modified files
	if modified_files:
		lines.append(f"Modified Files ({len(modified_files)}):")
		lines.append("─" * 80)
		for pair in modified_files:
			current_name = pair.get('fileB', '')
			baseline_name = pair.get('fileA', '')
			cd = pair.get('countings_delta')
			md = pair.get('metrics_delta')
			
			lines.append(f"  M {current_name}")
			if baseline_name != current_name:
				lines.append(f"      (was: {baseline_name})")
			
			if cd:
				delta_code = cd.get('code_lines', 0)
				delta_comment = cd.get('comment_lines', 0)
				delta_blank = cd.get('blank_lines', 0)
				sign_code = "+" if delta_code >= 0 else ""
				sign_comment = "+" if delta_comment >= 0 else ""
				sign_blank = "+" if delta_blank >= 0 else ""
				lines.append(f"      Code: {sign_code}{delta_code:>6}  Comment: {sign_comment}{delta_comment:>6}  Blank: {sign_blank}{delta_blank:>6}")
			
			if md:
				delta_func = md.get('func_count', 0)
				delta_avgcc = md.get('avg_cc', 0.0)
				delta_mi = md.get('mi', 0.0)
				sign_func = "+" if delta_func >= 0 else ""
				sign_avgcc = "+" if delta_avgcc >= 0 else ""
				sign_mi = "+" if delta_mi >= 0 else ""
				lines.append(f"      Functions: {sign_func}{delta_func:>4}  Avg CC: {sign_avgcc}{delta_avgcc:>6.2f}  MI: {sign_mi}{delta_mi:>6.2f}")
		lines.append("")
	
	# Complete File Table
	lines.append("-" * 80)
	lines.append("Complete File Table")
	lines.append("-" * 80)
	lines.append("")
	
	# Table header
	header = f"{'Current File':<40} {'Baseline File':<40} {'St':>3} {'ΔCode':>7} {'ΔComm':>7} {'ΔBlank':>7} {'ΔFunc':>6} {'ΔAvgCC':>8} {'ΔMI':>8}"
	lines.append(header)
	lines.append("─" * 140)
	
	# Sort pairs by current file name
	sorted_pairs = sorted(pairs, key=lambda p: p.get('fileB', p.get('fileA', '')).lower())
	
	for pair in sorted_pairs:
		current_name = pair.get('fileB', '')
		baseline_name = pair.get('fileA', '')
		counts = pair.get('counts', {})
		
		# Status: A=added, D=deleted, M=modified, U=unmodified
		if counts.get('added', 0) > 0:
			status = 'A'
		elif counts.get('deleted', 0) > 0:
			status = 'D'
		elif counts.get('modified', 0) > 0:
			status = 'M'
		else:
			status = '='
		
		cd = pair.get('countings_delta')
		md = pair.get('metrics_delta')
		cur_m = pair.get('current_metrics')
		
		# Format deltas
		def _fmt_delta(val, is_float=False, width=7):
			if val is None or val == 0:
				return ' ' * width
			sign = '+' if val >= 0 else ''
			if is_float:
				return f"{sign}{val:>{width-1}.2f}"
			else:
				return f"{sign}{val:>{width-1}}"
		
		delta_code = _fmt_delta(cd.get('code_lines') if cd else None)
		delta_comment = _fmt_delta(cd.get('comment_lines') if cd else None)
		delta_blank = _fmt_delta(cd.get('blank_lines') if cd else None)
		delta_func = _fmt_delta(md.get('func_count') if md else None, width=6)
		delta_avgcc = _fmt_delta(md.get('avg_cc') if md else None, is_float=True, width=8)
		delta_mi = _fmt_delta(md.get('mi') if md else None, is_float=True, width=8)
		
		# Truncate long filenames
		cur_display = current_name[-38:] if len(current_name) > 40 else current_name
		base_display = baseline_name[-38:] if len(baseline_name) > 40 else baseline_name
		
		row = f"{cur_display:<40} {base_display:<40} {status:>3} {delta_code:>7} {delta_comment:>7} {delta_blank:>7} {delta_func:>6} {delta_avgcc:>8} {delta_mi:>8}"
		lines.append(row)
	
	lines.append("")
	lines.append(f"Legend: St = Status (A=Added, D=Deleted, M=Modified, ==Unmodified)")
	lines.append("")
	
	# Footer
	lines.append("=" * 80)
	lines.append("End of Report".center(80))
	lines.append("=" * 80)
	
	# Write to file
	try:
		with open(output_path, 'w', encoding='utf-8') as f:
			f.write('\n'.join(lines))
		return True
	except Exception as e:
		print(f"Failed to write report: {e}")
		return False
