"""Generate Contracts analysis-comparison PDF for Cuong (May 22, 2026).

Compares student's analysis vs model answer issue-by-issue,
with commentary and conclusory-vs-proper rewrites.
"""

from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.lib.colors import HexColor
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
import os

NAVY      = HexColor("#1a2744")
GOLD      = HexColor("#c9a227")
MED_TEXT  = HexColor("#2d3748")
LIGHT_TEXT = HexColor("#4a5568")
BORDER    = HexColor("#d4cfc5")
WARM_BG   = HexColor("#fdf6ee")
COOL_BG   = HexColor("#eef5ee")
ACTION_BG = HexColor("#f0f4ff")
REWRITE_BEFORE = HexColor("#fce8e8")
REWRITE_AFTER  = HexColor("#e2f0e2")

def make_styles():
    s = {}
    s["title"] = ParagraphStyle("title", fontName="Helvetica-Bold", fontSize=15,
        textColor=NAVY, alignment=TA_LEFT, spaceAfter=1, leading=18)
    s["subtitle"] = ParagraphStyle("subtitle", fontName="Helvetica", fontSize=9,
        textColor=LIGHT_TEXT, alignment=TA_LEFT, spaceAfter=8, leading=11)
    s["h1"] = ParagraphStyle("h1", fontName="Helvetica-Bold", fontSize=11,
        textColor=NAVY, spaceBefore=10, spaceAfter=3, leading=13)
    s["h2"] = ParagraphStyle("h2", fontName="Helvetica-Bold", fontSize=9,
        textColor=MED_TEXT, spaceBefore=5, spaceAfter=2, leading=11)
    s["body"] = ParagraphStyle("body", fontName="Helvetica", fontSize=8.5,
        textColor=MED_TEXT, alignment=TA_JUSTIFY, leading=11.5,
        spaceBefore=1, spaceAfter=3)
    s["essay"] = ParagraphStyle("essay", fontName="Helvetica", fontSize=8,
        textColor=HexColor("#374151"), alignment=TA_JUSTIFY, leading=10.5)
    s["action"] = ParagraphStyle("action", fontName="Helvetica", fontSize=8.5,
        textColor=HexColor("#1e3a5f"), alignment=TA_LEFT, leading=11.5,
        spaceBefore=1, spaceAfter=1)
    s["rewrite_label"] = ParagraphStyle("rewrite_label", fontName="Helvetica-Bold",
        fontSize=7.5, textColor=LIGHT_TEXT, leading=10, spaceBefore=0, spaceAfter=1)
    s["rewrite"] = ParagraphStyle("rewrite", fontName="Helvetica", fontSize=8,
        textColor=MED_TEXT, alignment=TA_JUSTIFY, leading=10.5)
    s["footer"] = ParagraphStyle("footer", fontName="Helvetica", fontSize=7,
        textColor=LIGHT_TEXT, alignment=TA_LEFT, leading=9)
    return s

ST = make_styles()

def shaded(text, bg, pad=6):
    t = Table([[Paragraph(text, ST["essay"])]], colWidths=["100%"])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("LEFTPADDING", (0,0), (-1,-1), pad), ("RIGHTPADDING", (0,0), (-1,-1), pad),
        ("TOPPADDING", (0,0), (-1,-1), pad), ("BOTTOMPADDING", (0,0), (-1,-1), pad),
        ("BOX", (0,0), (-1,-1), 0.3, BORDER),
    ]))
    return t

def action_box(text):
    t = Table([[Paragraph(text, ST["action"])]], colWidths=["100%"])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), ACTION_BG),
        ("LEFTPADDING", (0,0), (-1,-1), 8), ("RIGHTPADDING", (0,0), (-1,-1), 8),
        ("TOPPADDING", (0,0), (-1,-1), 5), ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ]))
    return t

def rewrite_pair(before_text, after_text):
    before_parts = [
        [Paragraph("<b>CONCLUSORY</b>", ST["rewrite_label"]),
         Paragraph(before_text, ST["rewrite"])]
    ]
    after_parts = [
        [Paragraph("<b>REWRITTEN</b>", ST["rewrite_label"]),
         Paragraph(after_text, ST["rewrite"])]
    ]
    bt = Table(before_parts, colWidths=["100%"])
    bt.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), REWRITE_BEFORE),
        ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 6),
        ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("BOX", (0,0), (-1,-1), 0.3, BORDER),
    ]))
    at = Table(after_parts, colWidths=["100%"])
    at.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), REWRITE_AFTER),
        ("LEFTPADDING", (0,0), (-1,-1), 6), ("RIGHTPADDING", (0,0), (-1,-1), 6),
        ("TOPPADDING", (0,0), (-1,-1), 4), ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("BOX", (0,0), (-1,-1), 0.3, BORDER),
    ]))
    return [bt, Spacer(1, 2), at, Spacer(1, 6)]

def thin_hr():
    return HRFlowable(width="100%", thickness=0.4, color=BORDER, spaceAfter=3, spaceBefore=4)

def gold_hr():
    return HRFlowable(width="25%", thickness=1, color=GOLD, spaceAfter=4, spaceBefore=2)


def build():
    output_dir = r"C:\Users\sallen\Desktop\SHEP\BAR PREP by SHEP\STUDENT ANSWERS\Cuong"
    output_path = os.path.join(output_dir, "Cuong_Contracts_Analysis.pdf")
    doc = SimpleDocTemplate(output_path, pagesize=letter,
        leftMargin=0.65*inch, rightMargin=0.65*inch,
        topMargin=0.55*inch, bottomMargin=0.5*inch)
    story = []

    story.append(Paragraph("Deepening Your Analysis: Contracts", ST["title"]))
    story.append(gold_hr())
    story.append(Paragraph("Cuong  |  Band 2/6  |  May 22, 2026", ST["subtitle"]))
    story.append(Paragraph(
        "On the bar exam, <b>analysis</b> is where you earn the most points. The rule statement "
        "shows you know the law. The analysis shows you can <i>use</i> it. Analysis means taking "
        "the specific facts from the prompt and explaining, step by step, why they satisfy or fail "
        "each element of the rule. A conclusion without this reasoning is just an assertion -- the "
        "grader has no evidence you understood the problem. Below, we compare the analysis portions "
        "of your essay against a model answer, with specific ways to strengthen each one.",
        ST["body"]))
    story.append(Spacer(1, 2))

    # ---- Issue 1: Neighbor vs Painter ----
    story.append(thin_hr())
    story.append(Paragraph("Issue 1: Can the Neighbor Sue the Painter for Breach?", ST["h1"]))
    story.append(Paragraph("Your analysis:", ST["h2"]))
    story.append(shaded(
        "When there are valid offer, acceptance, and consideration of a contract between two "
        "parties, then that contract is legally binding. When one party changes the terms or "
        "transfers the contract to another person without the original party's consent, then "
        "there is not a valid assignment. There was no valid assignment of the homeowner's "
        "contractual obligations to the neighbor. Because there is no valid assignment, the "
        "neighbor would not have a valid breach of contract action against the painter.",
        WARM_BG))
    story.append(Paragraph("Model analysis:", ST["h2"]))
    story.append(shaded(
        "The neighbor was not a party to the original homeowner-painter contract. For the "
        "neighbor to enforce the contract, the neighbor must establish either (a) a valid "
        "assignment of the homeowner's rights, or (b) status as an intended third-party "
        "beneficiary. Assignment of rights transfers the right to receive performance to a "
        "third party. Here, the homeowner attempted to redirect the painter's performance from "
        "his own house to the neighbor's -- but this changes the nature of the obligation, not "
        "just who receives it. A change in the location and subject of the work is a material "
        "modification, not a simple assignment. Without a new agreement between the painter and "
        "the neighbor supported by consideration, the neighbor has no privity and cannot maintain "
        "a breach of contract action.",
        COOL_BG))
    story.append(Paragraph(
        "You reached the right conclusion -- the neighbor cannot sue -- but your reasoning has "
        "a critical doctrinal error that would cost significant points. You conflated <i>assignment "
        "of rights</i> with <i>delegation of duties</i>. An assignment transfers a <b>right</b> "
        "to receive performance. A delegation transfers a <b>duty</b> to perform. You wrote that "
        "the homeowner tried to assign \"contractual obligations\" -- obligations are duties, not "
        "rights. This confusion signals to the grader that you do not understand the distinction, "
        "which is a core concept the question is testing. Additionally, your analysis is conclusory: "
        "you state there is no valid assignment but never explain <i>what</i> a valid assignment "
        "requires or <i>why</i> the facts here fail those requirements.",
        ST["body"]))
    story.append(action_box(
        "<b>Build this habit:</b> Before writing about assignment or delegation, pause and "
        "ask: am I talking about a right or a duty? \"Assignment transfers a right to receive "
        "performance. Delegation transfers a duty to perform.\" Writing these definitions out "
        "first prevents the conflation and earns separate points for each concept."))

    # ---- Issue 2: Retiree as Third-Party Beneficiary ----
    story.append(thin_hr())
    story.append(Paragraph("Issue 2: Can the Retiree Sue for Breach of Contract?", ST["h1"]))
    story.append(Paragraph("Your analysis:", ST["h2"]))
    story.append(shaded(
        "The retiree would not succeed in a breach of contract action because the retiree is not "
        "a valid assignee or not part of the delegation of duties from the original parties between "
        "the homeowner and the painter. Although the retiree wanted both the homeowner and neighbor "
        "to paint their houses to increase their property values, the retiree is not part of the "
        "homeowner and the painter's original contract. The retiree has no interest whatsoever in "
        "the contracts between the homeowner and the painter.",
        WARM_BG))
    story.append(Paragraph("Model analysis:", ST["h2"]))
    story.append(shaded(
        "The retiree's claim depends on third-party beneficiary status, not assignment or "
        "delegation. A third-party beneficiary can enforce a contract if the contracting parties "
        "intended the performance to benefit the third party (an intended beneficiary). If the "
        "benefit is merely incidental, the third party has no standing. Here, the homeowner "
        "contracted to have his house painted for his own benefit. The retiree's benefit -- "
        "improved property values and neighborhood aesthetics -- is a byproduct, not the purpose "
        "of the contract. The retiree is an incidental beneficiary and therefore cannot enforce "
        "the contract against the painter.",
        COOL_BG))
    story.append(Paragraph(
        "This is the most significant gap in your essay. The question is testing whether you "
        "recognize the <b>third-party beneficiary</b> doctrine, and you missed it entirely. "
        "Instead, you analyzed the retiree's claim through assignment and delegation -- which "
        "are the wrong frameworks. The retiree never received a transfer of rights from anyone. "
        "The question is whether the retiree was an <i>intended</i> or <i>incidental</i> "
        "beneficiary of the original contract. An intended beneficiary can sue; an incidental "
        "beneficiary cannot. The facts clearly make the retiree incidental -- the homeowner "
        "contracted for his own house, not to improve the retiree's property values. Spotting "
        "the correct doctrine is worth more than a full analysis of the wrong one.",
        ST["body"]))
    story.append(action_box(
        "<b>Build this habit:</b> When a non-party wants to enforce a contract, run through "
        "a checklist: (1) Are they an assignee? (2) Are they an intended third-party "
        "beneficiary? (3) Are they merely an incidental beneficiary? Each theory has different "
        "elements. Identify which theory fits before analyzing it."))

    # ---- Issue 3: Painter's Claim Against the Neighbor ----
    story.append(thin_hr())
    story.append(Paragraph("Issue 3: Can the Painter Recover from the Neighbor?", ST["h1"]))
    story.append(Paragraph("Your analysis:", ST["h2"]))
    story.append(shaded(
        "Presuming that the painter paints the neighbor's house, that performed party made "
        "substantial performance to complete the contract. When the painter substantially "
        "performed to paint the house under an implied in fact contract, then the painter is "
        "a valid party to the valid contract with the neighbor. A court would find that the "
        "painter will get the $6,000 because he substantially performed his part of the "
        "contract with the neighbor.",
        WARM_BG))
    story.append(Paragraph("Model analysis:", ST["h2"]))
    story.append(shaded(
        "There is no express contract between the painter and the neighbor -- the neighbor never "
        "agreed to hire the painter or to pay $6,000. However, the painter may recover under two "
        "alternative theories. First, an implied-in-fact contract: if the neighbor knew the "
        "painter was painting her house and accepted the benefit without objecting, her conduct "
        "manifests assent to pay for the services. The elements are mutual assent shown through "
        "conduct and an expectation of compensation. Second, even without an implied contract, "
        "the painter can recover under unjust enrichment (quasi-contract): the neighbor received "
        "a benefit (a freshly painted house), the painter conferred it expecting payment, and "
        "it would be unjust for the neighbor to retain the benefit without paying. Recovery would "
        "be the reasonable value of the services, which may differ from the $6,000 contract price.",
        COOL_BG))
    story.append(Paragraph(
        "You identified the right general theory -- implied-in-fact contract -- but misapplied "
        "a key doctrine. <b>Substantial performance</b> determines whether a party has fulfilled "
        "enough of their obligations under an <i>existing</i> contract. It does not create a "
        "contract where none existed. You used it as if completing the painting work creates "
        "contractual privity with the neighbor. It does not. The correct framework is: did the "
        "neighbor's conduct (knowing about and accepting the painting) manifest assent to an "
        "implied agreement? Alternatively, does unjust enrichment apply? You also missed the "
        "distinction between the $6,000 contract price (which applies to the homeowner contract) "
        "and the reasonable value of services (which is what the painter could recover from the "
        "neighbor under quasi-contract).",
        ST["body"]))
    story.append(action_box(
        "<b>Build this habit:</b> Before using a legal doctrine, state what it does in one "
        "sentence. \"Substantial performance means a party has completed enough of their "
        "contractual duties to trigger the other side's obligation to pay.\" If that definition "
        "does not fit the situation you are analyzing, you are using the wrong doctrine."))

    # ---- Issue 4: Painter's Claim Against the Homeowner ----
    story.append(thin_hr())
    story.append(Paragraph("Issue 4: Can the Painter Recover from the Homeowner?", ST["h1"]))
    story.append(Paragraph("Your analysis:", ST["h2"]))
    story.append(shaded(
        "The painter would succeed in a contract claim against the homeowner because the "
        "homeowner transferred the contract obligations to the neighbor without the painter's "
        "consent. When a party transfer the rights to a third party without the other party "
        "knowing it, then there is a breach of contract.",
        WARM_BG))
    story.append(Paragraph("Model analysis:", ST["h2"]))
    story.append(shaded(
        "The homeowner is the original contracting party and remains liable under the contract. "
        "The homeowner directed the painter to paint the neighbor's house instead of his own. "
        "The painter performed as directed. A delegation of duties does not automatically release "
        "the delegator from liability -- the delegator remains responsible unless there is a "
        "novation (an express agreement among all parties to substitute a new obligor). The "
        "painter never agreed to release the homeowner. Without a novation, the homeowner's "
        "obligation to pay $6,000 remains intact.",
        COOL_BG))
    story.append(Paragraph(
        "You reached the right conclusion -- the painter can recover from the homeowner -- but "
        "your reasoning is muddled. You framed it as a breach caused by an unauthorized "
        "\"transfer\" of obligations, when the simpler and stronger argument is: the homeowner "
        "is the original contracting party, he directed the painter to perform elsewhere, the "
        "painter performed as directed, and the homeowner's payment obligation remains. The core "
        "doctrine is the <b>delegator's continuing liability</b>: delegation does not release "
        "the original party unless there is a novation. You did not mention novation at all.",
        ST["body"]))
    story.append(action_box(
        "<b>Build this habit:</b> Start with the simplest theory that reaches the right result. "
        "\"The homeowner promised to pay $6,000. The painter performed. The homeowner must pay.\" "
        "Only reach for more complex doctrines when the simple theory does not work. Then ask: "
        "\"Was there a novation?\" If no, the original party remains liable."))

    # ---- Conclusory vs. Proper ----
    story.append(Spacer(1, 4))
    story.append(HRFlowable(width="100%", thickness=0.8, color=GOLD, spaceAfter=4, spaceBefore=6))
    story.append(Paragraph("Conclusory Analysis vs. Proper Analysis", ST["h1"]))
    story.append(Paragraph(
        "Below are specific sentences from your essay rewritten to show the difference. The "
        "conclusory version states the outcome. The rewritten version explains <i>why</i> the "
        "facts lead there.",
        ST["body"]))

    story.append(Paragraph("<i>Issue 1 -- No valid assignment</i>", ST["h2"]))
    story.extend(rewrite_pair(
        "There was no valid assignment of the homeowner's contractual obligations to the "
        "neighbor. Because there is no valid assignment, the neighbor would not have a valid "
        "breach of contract action against the painter.",
        "The neighbor was not a party to the original homeowner-painter contract. The homeowner "
        "attempted to redirect the painter's performance to a different house, but this changes "
        "the nature and location of the work -- it is a material modification, not a simple "
        "assignment of rights. Without a separate agreement between the painter and the neighbor "
        "supported by consideration, the neighbor lacks privity and cannot sue for breach."
    ))

    story.append(Paragraph("<i>Issue 2 -- Retiree's standing</i>", ST["h2"]))
    story.extend(rewrite_pair(
        "The retiree is not a valid assignee or not part of the delegation of duties from the "
        "original parties. The retiree has no interest whatsoever in the contracts between the "
        "homeowner and the painter.",
        "The retiree was never assigned any rights and was never delegated any duties. The "
        "correct framework is third-party beneficiary. The homeowner contracted to have his own "
        "house painted -- the retiree's benefit (improved neighborhood aesthetics and property "
        "values) is incidental, not the purpose of the contract. As an incidental beneficiary, "
        "the retiree has no standing to enforce the agreement."
    ))

    story.append(Paragraph("<i>Issue 3 -- Substantial performance</i>", ST["h2"]))
    story.extend(rewrite_pair(
        "When the painter substantially performed to paint the house under an implied in fact "
        "contract, then the painter is a valid party to the valid contract with the neighbor.",
        "There is no express contract between the painter and the neighbor. However, if the "
        "neighbor knew the painting was happening and accepted the benefit without objecting, "
        "her conduct manifests assent to an implied-in-fact contract. Alternatively, the painter "
        "can recover under unjust enrichment: the neighbor received a valuable benefit and it "
        "would be unjust to keep it without paying."
    ))

    story.append(Paragraph("<i>Issue 4 -- Homeowner's liability</i>", ST["h2"]))
    story.extend(rewrite_pair(
        "The painter would succeed in a contract claim against the homeowner because the "
        "homeowner transferred the contract obligations to the neighbor without the painter's "
        "consent.",
        "The homeowner is the original contracting party who promised to pay $6,000 for painting "
        "services. He directed the painter to paint the neighbor's house, and the painter "
        "performed as directed. A delegation of duties does not release the delegator unless "
        "there is a novation. The painter never agreed to release the homeowner, so the "
        "homeowner remains liable for the full $6,000."
    ))

    # ---- Closing ----
    story.append(HRFlowable(width="100%", thickness=0.4, color=BORDER, spaceAfter=4, spaceBefore=6))
    story.append(Paragraph(
        "This essay shows that you are engaging with the material and attempting to use legal "
        "structure -- you organized by issue and tried to follow an IRAC format. That foundation "
        "matters. The gaps are in two areas that are fixable with focused practice. First, "
        "<b>doctrinal precision</b>: you must distinguish assignment from delegation, know what "
        "substantial performance actually does, and recognize third-party beneficiary as a "
        "separate doctrine from assignment. These are discrete rules you can drill. Second, "
        "<b>analytical bridges</b>: every conclusion needs a sentence that connects the specific "
        "facts to the specific elements of the rule. \"The neighbor cannot sue\" is a conclusion. "
        "\"The neighbor cannot sue because she was not a party to the contract, was not assigned "
        "any rights, and was not an intended beneficiary\" is analysis. The difference between "
        "those two sentences is the difference between a 2 and a 4.",
        ST["body"]))
    story.append(Spacer(1, 10))
    story.append(Paragraph("Bar Prep by SHEP  |  May 22, 2026", ST["footer"]))
    doc.build(story)
    return output_path


if __name__ == "__main__":
    path = build()
    print(f"Analysis: {path}")
