"""B1.2 非官方参考实现：分析附件，不作真实市场投资判断。"""
from pathlib import Path
import base64, html, io, json
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import font_manager

BASE = Path(__file__).resolve().parent if '__file__' in globals() else Path.cwd()
OUT = BASE / 'B1.2_output'
OUT.mkdir(exist_ok=True)
available = {f.name for f in font_manager.fontManager.ttflist}
font = next((f for f in ['Microsoft YaHei', 'SimHei', 'Noto Sans CJK SC'] if f in available), 'DejaVu Sans')
plt.rcParams.update({'font.sans-serif':[font], 'axes.unicode_minus':False, 'figure.dpi':120})

def read_csv(name):
    candidates = [Path.cwd()/name, BASE/name, BASE.parent/'materials'/name]
    path = next((p for p in candidates if p.is_file()), None)
    if path is None: raise FileNotFoundError(f'请将 {name} 与参考代码放在同一目录')
    return pd.read_csv(path)

housing_data = read_csv('housing_transactions.csv')
market_data = read_csv('market_data.csv')
housing_data['transaction_date'] = pd.to_datetime(housing_data['transaction_date'], errors='raise')
market_data['date'] = pd.to_datetime(market_data['date'], errors='raise')
for col in ['area','price','unit_price']:
    housing_data[col] = pd.to_numeric(housing_data[col], errors='raise')
if housing_data[['region','house_type','transaction_date','area','price','unit_price']].isna().any().any():
    raise ValueError('关键字段存在缺失，应先确认并记录处理策略')
if (housing_data[['area','price','unit_price']] <= 0).any().any():
    raise ValueError('面积和价格必须为正值')

# 区域价格以成交单价为口径，避免面积对总价的混淆。
avg_price_by_region = housing_data.groupby('region')['unit_price'].mean().sort_values()
transaction_count_by_type = housing_data['house_type'].value_counts()
housing_data['month'] = housing_data['transaction_date'].dt.to_period('M').astype(str)
market_data['month'] = market_data['date'].dt.to_period('M').astype(str)
monthly_price = housing_data.groupby('month', as_index=False).agg(avg_price=('unit_price','mean'))
monthly_rate = market_data.groupby('month', as_index=False).agg(interest_rate=('interest_rate','mean'))
risk_trend = pd.merge(monthly_price, monthly_rate, on='month', how='inner').sort_values('month')
region_trend = housing_data.groupby(['month','region'])['unit_price'].mean().unstack('region')
if risk_trend.empty: raise ValueError('交易与市场数据没有可匹配月份')

def image(fig):
    buffer = io.BytesIO();fig.savefig(buffer,format='png',bbox_inches='tight');plt.close(fig)
    return 'data:image/png;base64,' + base64.b64encode(buffer.getvalue()).decode('ascii')

fig, ax = plt.subplots(figsize=(7,4))
avg_price_by_region.plot.bar(ax=ax,color='#2466b5');ax.set(title='区域平均成交单价',xlabel='区域',ylabel='元/平方米')
img_region = image(fig)
fig, ax = plt.subplots(figsize=(7,4))
transaction_count_by_type.plot.bar(ax=ax,color='#2466b5',rot=15);ax.set(title='各户型交易数量',xlabel='户型',ylabel='交易数')
img_types = image(fig)
fig, ax = plt.subplots(figsize=(8,4))
region_trend.plot(ax=ax,marker='o');ax.set(title='各区域月度成交单价趋势',xlabel='月份',ylabel='元/平方米')
img_trend = image(fig)
fig, ax = plt.subplots(figsize=(8,4))
ax.plot(risk_trend['month'],risk_trend['avg_price'],color='#1754b8',marker='o',label='平均单价')
ax.set_ylabel('成交单价（元/平方米）',color='#1754b8');ax.tick_params(axis='x',rotation=45)
ax2=ax.twinx();ax2.plot(risk_trend['month'],risk_trend['interest_rate'],color='#a64a10',marker='s',label='利率')
ax2.set_ylabel('商贷利率（%）',color='#a64a10');ax.set_title('房价与利率月度趋势（双轴尺度）')
fig.tight_layout();img_risk=image(fig)

correlation = risk_trend['avg_price'].corr(risk_trend['interest_rate'])
price_gap=(housing_data['price']-housing_data['area']*housing_data['unit_price']/10000).abs()
stats={'housing_rows':len(housing_data),'market_rows':len(market_data),'matched_months':len(risk_trend),
       'avg_unit_price_by_region':avg_price_by_region.round(2).to_dict(),
       'transactions_by_type':transaction_count_by_type.to_dict(),
       'monthly_price_rate_correlation':round(float(correlation),4),
       'price_identity_mismatches_over_0_02_wan':int((price_gap>0.02).sum()),
       'price_identity_median_gap_wan':round(float(price_gap.median()),4)}
print('区域平均单价（元/平方米）\n',avg_price_by_region.to_string())
print('\n户型交易数量\n',transaction_count_by_type.to_string())
print('\n月度价格与利率\n',risk_trend.to_string(index=False))
print('\n运行摘要\n',json.dumps(stats,ensure_ascii=False,indent=2))

avg_price_by_region.to_csv(OUT/'region_prices.csv',encoding='utf-8-sig')
transaction_count_by_type.to_csv(OUT/'house_type_counts.csv',encoding='utf-8-sig')
risk_trend.to_csv(OUT/'monthly_risk_trend.csv',index=False,encoding='utf-8-sig')
(OUT/'summary.json').write_text(json.dumps(stats,ensure_ascii=False,indent=2),encoding='utf-8')

def tbl(df):return '<div class="table">'+df.to_html(border=0,index=False,escape=True)+'</div>'
body='<h1>B1.2 参考代码运行结果</h1><p>非官方参考实现；以下数值由项目附件实际计算。样例不能代表真实市场。</p>'
body+='<h2>房屋定价</h2>'+tbl(avg_price_by_region.rename('平均单价').reset_index())+'<img alt="区域平均单价柱状图" src="'+img_region+'">'
body+='<img alt="区域月度单价趋势图" src="'+img_trend+'">'
body+='<p>样例区域单价呈固定值模式。R_02 较低、R_04 较高，只说明该样例的区域价格差异；还需控制房况和供需，不能直接判定投资价值。</p>'
body+='<h2>购房需求</h2>'+tbl(transaction_count_by_type.rename_axis('户型').rename('交易数').reset_index())+'<img alt="户型交易数量柱状图" src="'+img_types+'">'
body+='<p>交易最多的户型与其余户型差距需结合库存和样本规模分析，不能仅以数量判断全部用户需求。</p>'
body+='<h2>市场风险趋势</h2>'+tbl(risk_trend)+'<img alt="房价与利率双轴折线图" src="'+img_risk+'">'
body+='<p>月度相关系数为 '+str(stats['monthly_price_rate_correlation'])+'，仅 '+str(len(risk_trend))+' 个观测月份；相关性不证明因果。双轴图的刻度不同，应读取各自单位，不能凭曲线距离判断关系。</p>'
body+='<h2>质量与口径检查</h2><p>price 与 area×unit_price/10000 的绝对差超过 0.02 万元的记录数：'+str(stats['price_identity_mismatches_over_0_02_wan'])+'；绝对差中位数：'+str(stats['price_identity_median_gap_wan'])+' 万元。需要核对价格口径，未擅自修改原数据。</p>'
style='body{font:17px/1.8 system-ui,"Microsoft YaHei",sans-serif;color:#17263b;max-width:900px;margin:auto;padding:20px}img{width:100%;height:auto}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #dce4ee;padding:10px;text-align:left}.table{overflow:auto}h1{font-size:1.6rem}h2{font-size:1.25rem}'
report='<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>B1.2 参考运行结果</title><style>'+style+'</style><body><a href="../index.html#b12">返回学习资料</a>'+body+'</body></html>'
(BASE/'B1.2_reference.html').write_text(report,encoding='utf-8')
